From 774efe6635ed7cad04df6dddf3852b4e017f8ccf Mon Sep 17 00:00:00 2001
From: Luke Pulverenti
Date: Thu, 21 Jun 2018 13:39:36 -0400
Subject: [PATCH] rework storage of extras
---
BDInfo/BDInfo.csproj | 4 +-
BDInfo/packages.config | 2 +-
DvdLib/DvdLib.csproj | 4 +-
DvdLib/packages.config | 2 +-
Emby.Dlna/Emby.Dlna.csproj | 8 +-
Emby.Dlna/packages.config | 6 +-
.../Emby.Drawing.ImageMagick.csproj | 6 +-
Emby.Drawing.ImageMagick/packages.config | 4 +-
Emby.Drawing.Skia/Emby.Drawing.Skia.csproj | 6 +-
Emby.Drawing.Skia/packages.config | 4 +-
Emby.Drawing/Emby.Drawing.csproj | 6 +-
Emby.Drawing/packages.config | 4 +-
Emby.Photos/Emby.Photos.csproj | 6 +-
Emby.Photos/packages.config | 4 +-
.../ApplicationHost.cs | 5 +-
.../Data/SqliteItemRepository.cs | 259 +-
.../Devices/DeviceManager.cs | 150 +-
.../Devices/SqliteDeviceRepository.cs | 362 +--
Emby.Server.Implementations/Dto/DtoService.cs | 31 +-
.../Emby.Server.Implementations.csproj | 24 +-
.../HttpServer/Security/AuthService.cs | 4 +-
.../Security/AuthorizationContext.cs | 45 +-
.../HttpServer/Security/SessionContext.cs | 2 +-
.../IO/ManagedFileSystem.cs | 8 +-
.../Library/LibraryManager.cs | 12 +-
.../Library/LocalTrailerPostScanTask.cs | 106 -
.../Library/UserDataManager.cs | 12 +-
.../Library/UserManager.cs | 2 +-
.../Networking/NetworkManager.cs | 3 +-
.../ScheduledTasks/PluginUpdateTask.cs | 15 +-
.../Security/AuthenticationRepository.cs | 65 +-
.../Session/FirebaseSessionController.cs | 2 +-
.../Session/SessionManager.cs | 188 +-
Emby.Server.Implementations/packages.config | 12 +-
MediaBrowser.Api/BaseApiService.cs | 2 +-
MediaBrowser.Api/Devices/DeviceService.cs | 63 +-
MediaBrowser.Api/Library/LibraryService.cs | 4 +-
MediaBrowser.Api/MediaBrowser.Api.csproj | 6 +-
MediaBrowser.Api/Session/SessionsService.cs | 17 +-
.../UserLibrary/BaseItemsRequest.cs | 2 +
MediaBrowser.Api/UserLibrary/ItemsService.cs | 30 +-
.../UserLibrary/UserLibraryService.cs | 59 +-
MediaBrowser.Api/packages.config | 4 +-
.../MediaBrowser.LocalMetadata.csproj | 6 +-
.../Parsers/BaseItemXmlParser.cs | 16 +-
.../Savers/BaseXmlSaver.cs | 18 +-
MediaBrowser.LocalMetadata/packages.config | 4 +-
.../Manager/ProviderManager.cs | 16 +-
.../Manager/ProviderUtils.cs | 10 +-
.../MediaBrowser.Providers.csproj | 8 +-
.../Movies/GenericMovieDbInfo.cs | 15 +-
MediaBrowser.Providers/packages.config | 6 +-
.../MediaBrowser.Server.Mono.csproj | 20 +-
MediaBrowser.Server.Mono/Program.cs | 2 +-
MediaBrowser.Server.Mono/packages.config | 11 +-
MediaBrowser.ServerApplication/MainStartup.cs | 2 +-
.../MediaBrowser.ServerApplication.csproj | 20 +-
.../packages.config | 11 +-
MediaBrowser.Tests/MediaBrowser.Tests.csproj | 6 +-
MediaBrowser.Tests/packages.config | 4 +-
.../MediaBrowser.WebDashboard.csproj | 6 +-
.../emby-apiclient/sync/mediasync.js | 2 +-
.../emby-webcomponents/cardbuilder/card.css | 2 +-
...screen-doubleclick.js => fullscreen-dc.js} | 0
.../emby-webcomponents/strings/en-us.json | 3 +-
.../emby-webcomponents/sync/sync.js | 2 +-
.../emby-webcomponents/sync/syncjoblist.js | 2 +-
.../emby-webcomponents/themes/dark/theme.css | 2 +-
.../components/filterdialog/filterdialog.js | 2 +-
.../filterdialog/filterdialog.template.html | 5 +
.../dashboard-ui/css/librarybrowser.css | 2 +-
.../dashboard-ui/device.html | 36 -
.../dashboard-ui/devices.html | 10 +-
.../dashboard-ui/scripts/dashboardpage.js | 4 +-
.../dashboard-ui/scripts/device.js | 1 -
.../dashboard-ui/scripts/devices.js | 2 +-
.../scripts/itembynamedetailpage.js | 2 +-
.../dashboard-ui/scripts/itemdetailpage.js | 4 +-
.../dashboard-ui/scripts/site.js | 4 +-
.../dashboard-ui/scripts/userlibraryaccess.js | 2 +-
MediaBrowser.WebDashboard/packages.config | 4 +-
.../MediaBrowser.XbmcMetadata.csproj | 6 +-
.../Parsers/BaseNfoParser.cs | 10 +-
.../Savers/BaseNfoSaver.cs | 8 +-
MediaBrowser.XbmcMetadata/packages.config | 4 +-
Mono.Nat/Mono.Nat.csproj | 4 +-
Mono.Nat/packages.config | 2 +-
RSSDP/RSSDP.csproj | 4 +-
RSSDP/packages.config | 2 +-
SharedVersion.cs | 2 +-
SocketHttpListener/SocketHttpListener.csproj | 4 +-
SocketHttpListener/packages.config | 2 +-
ThirdParty/emby/Emby.Server.Connect.dll | Bin 62976 -> 64512 bytes
ThirdParty/emby/Emby.Server.MediaEncoding.dll | Bin 257024 -> 257024 bytes
ThirdParty/emby/Emby.Server.Sync.dll | Bin 174592 -> 174592 bytes
.../MediaBrowser.Common.3.3.50-beta.nupkg | Bin 159927 -> 0 bytes
.../lib/netstandard2.0/MediaBrowser.Model.dll | Bin 399360 -> 0 bytes
.../MediaBrowser.Common.3.3.53-beta.nupkg | Bin 0 -> 159389 bytes
.../netstandard2.0/MediaBrowser.Common.dll | Bin
.../lib/netstandard2.0/MediaBrowser.Model.dll | Bin 0 -> 398336 bytes
.../MediaBrowser.Naming.1.1.5-beta.nupkg | Bin 25511 -> 0 bytes
.../MediaBrowser.Naming.1.1.6-beta.nupkg | Bin 0 -> 25501 bytes
.../lib/netstandard2.0/Emby.Naming.dll | Bin 59904 -> 59904 bytes
...MediaBrowser.Server.Core.3.3.50-beta.nupkg | Bin 2969145 -> 0 bytes
...MediaBrowser.Server.Core.3.3.53-beta.nupkg | Bin 0 -> 2965713 bytes
.../MediaBrowser.Controller.dll | Bin 6596096 -> 6588416 bytes
.../ServiceStack.Text.4.5.8.nupkg | Bin 467606 -> 0 bytes
.../lib/net45/ServiceStack.Text.dll | Bin 350208 -> 0 bytes
.../ServiceStack.Text.dll | Bin 328704 -> 0 bytes
.../lib/sl5/ServiceStack.Text.dll | Bin 379904 -> 0 bytes
.../lib/sl5/ServiceStack.Text.xml | 2375 -----------------
.../ServiceStack.Text.5.1.0.nupkg | Bin 0 -> 361663 bytes
.../lib/net45/ServiceStack.Text.dll | Bin 0 -> 411648 bytes
.../lib/net45/ServiceStack.Text.xml | 1612 +++++++++++
.../ServiceStack.Text.deps.json | 240 ++
.../lib/netstandard2.0/ServiceStack.Text.dll | Bin 0 -> 401408 bytes
.../lib/netstandard2.0}/ServiceStack.Text.xml | 148 +-
.../SharpCompress.0.18.2.nupkg | Bin 765122 -> 0 bytes
.../lib/net35/SharpCompress.dll | Bin 454656 -> 0 bytes
.../lib/net45/SharpCompress.dll | Bin 456192 -> 0 bytes
.../lib/netstandard1.0/SharpCompress.dll | Bin 438272 -> 0 bytes
.../lib/netstandard1.3/SharpCompress.dll | Bin 456192 -> 0 bytes
.../SharpCompress.0.21.1.nupkg | Bin 0 -> 1080610 bytes
.../lib/net35/SharpCompress.dll | Bin 0 -> 528384 bytes
.../lib/net45/SharpCompress.dll | Bin 0 -> 530944 bytes
.../lib/netstandard1.0/SharpCompress.dll | Bin 0 -> 510464 bytes
.../lib/netstandard1.3/SharpCompress.dll | Bin 0 -> 532992 bytes
.../lib/netstandard2.0/SharpCompress.dll | Bin 0 -> 532992 bytes
...untime.CompilerServices.Unsafe.4.5.0.nupkg | Bin 90606 -> 0 bytes
.../lib/uap10.0.16300/_._ | 0
.../ref/uap10.0.16300/_._ | 0
.../version.txt | 1 -
.../.signature.p7s | Bin 9355 -> 9355 bytes
.../LICENSE.TXT | 0
...untime.CompilerServices.Unsafe.4.5.1.nupkg | Bin 0 -> 90384 bytes
.../THIRD-PARTY-NOTICES.TXT | 0
...System.Runtime.CompilerServices.Unsafe.dll | Bin 21648 -> 21640 bytes
...System.Runtime.CompilerServices.Unsafe.xml | 0
...System.Runtime.CompilerServices.Unsafe.dll | Bin 22160 -> 22160 bytes
...System.Runtime.CompilerServices.Unsafe.xml | 0
...System.Runtime.CompilerServices.Unsafe.dll | Bin 22160 -> 22184 bytes
...System.Runtime.CompilerServices.Unsafe.xml | 0
...System.Runtime.CompilerServices.Unsafe.dll | Bin 23176 -> 23720 bytes
...System.Runtime.CompilerServices.Unsafe.xml | 0
...System.Runtime.CompilerServices.Unsafe.dll | Bin 23696 -> 24208 bytes
...System.Runtime.CompilerServices.Unsafe.xml | 0
.../useSharedDesignerContext.txt | 0
.../version.txt | 1 +
.../.signature.p7s | Bin 9355 -> 0 bytes
.../LICENSE.TXT | 23 -
...tem.Threading.Tasks.Extensions.4.5.0.nupkg | Bin 109001 -> 0 bytes
.../THIRD-PARTY-NOTICES.TXT | 309 ---
.../lib/netcoreapp2.1/_._ | 0
.../System.Threading.Tasks.Extensions.dll | Bin 32912 -> 0 bytes
.../System.Threading.Tasks.Extensions.xml | 166 --
.../System.Threading.Tasks.Extensions.dll | Bin 32904 -> 0 bytes
.../System.Threading.Tasks.Extensions.xml | 166 --
.../System.Threading.Tasks.Extensions.dll | Bin 32912 -> 0 bytes
.../System.Threading.Tasks.Extensions.xml | 166 --
.../lib/uap10.0.16300/_._ | 0
.../ref/netcoreapp2.1/_._ | 0
.../System.Threading.Tasks.Extensions.dll | Bin 25744 -> 0 bytes
.../System.Threading.Tasks.Extensions.xml | 166 --
.../System.Threading.Tasks.Extensions.dll | Bin 25736 -> 0 bytes
.../System.Threading.Tasks.Extensions.xml | 166 --
.../ref/uap10.0.16300/_._ | 0
.../useSharedDesignerContext.txt | 0
.../version.txt | 1 -
168 files changed, 2674 insertions(+), 4746 deletions(-)
delete mode 100644 Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
rename MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fullscreen/{fullscreen-doubleclick.js => fullscreen-dc.js} (100%)
delete mode 100644 MediaBrowser.WebDashboard/dashboard-ui/device.html
delete mode 100644 MediaBrowser.WebDashboard/dashboard-ui/scripts/device.js
delete mode 100644 packages/MediaBrowser.Common.3.3.50-beta/MediaBrowser.Common.3.3.50-beta.nupkg
delete mode 100644 packages/MediaBrowser.Common.3.3.50-beta/lib/netstandard2.0/MediaBrowser.Model.dll
create mode 100644 packages/MediaBrowser.Common.3.3.53-beta/MediaBrowser.Common.3.3.53-beta.nupkg
rename packages/{MediaBrowser.Common.3.3.50-beta => MediaBrowser.Common.3.3.53-beta}/lib/netstandard2.0/MediaBrowser.Common.dll (100%)
create mode 100644 packages/MediaBrowser.Common.3.3.53-beta/lib/netstandard2.0/MediaBrowser.Model.dll
delete mode 100644 packages/MediaBrowser.Naming.1.1.5-beta/MediaBrowser.Naming.1.1.5-beta.nupkg
create mode 100644 packages/MediaBrowser.Naming.1.1.6-beta/MediaBrowser.Naming.1.1.6-beta.nupkg
rename packages/{MediaBrowser.Naming.1.1.5-beta => MediaBrowser.Naming.1.1.6-beta}/lib/netstandard2.0/Emby.Naming.dll (91%)
delete mode 100644 packages/MediaBrowser.Server.Core.3.3.50-beta/MediaBrowser.Server.Core.3.3.50-beta.nupkg
create mode 100644 packages/MediaBrowser.Server.Core.3.3.53-beta/MediaBrowser.Server.Core.3.3.53-beta.nupkg
rename packages/{MediaBrowser.Server.Core.3.3.50-beta => MediaBrowser.Server.Core.3.3.53-beta}/lib/netstandard2.0/MediaBrowser.Controller.dll (94%)
delete mode 100644 packages/ServiceStack.Text.4.5.8/ServiceStack.Text.4.5.8.nupkg
delete mode 100644 packages/ServiceStack.Text.4.5.8/lib/net45/ServiceStack.Text.dll
delete mode 100644 packages/ServiceStack.Text.4.5.8/lib/portable-net45+win8+monotouch+monoandroid+xamarin.ios10/ServiceStack.Text.dll
delete mode 100644 packages/ServiceStack.Text.4.5.8/lib/sl5/ServiceStack.Text.dll
delete mode 100644 packages/ServiceStack.Text.4.5.8/lib/sl5/ServiceStack.Text.xml
create mode 100644 packages/ServiceStack.Text.5.1.0/ServiceStack.Text.5.1.0.nupkg
create mode 100644 packages/ServiceStack.Text.5.1.0/lib/net45/ServiceStack.Text.dll
create mode 100644 packages/ServiceStack.Text.5.1.0/lib/net45/ServiceStack.Text.xml
create mode 100644 packages/ServiceStack.Text.5.1.0/lib/netstandard2.0/ServiceStack.Text.deps.json
create mode 100644 packages/ServiceStack.Text.5.1.0/lib/netstandard2.0/ServiceStack.Text.dll
rename packages/{ServiceStack.Text.4.5.8/lib/net45 => ServiceStack.Text.5.1.0/lib/netstandard2.0}/ServiceStack.Text.xml (96%)
delete mode 100644 packages/SharpCompress.0.18.2/SharpCompress.0.18.2.nupkg
delete mode 100644 packages/SharpCompress.0.18.2/lib/net35/SharpCompress.dll
delete mode 100644 packages/SharpCompress.0.18.2/lib/net45/SharpCompress.dll
delete mode 100644 packages/SharpCompress.0.18.2/lib/netstandard1.0/SharpCompress.dll
delete mode 100644 packages/SharpCompress.0.18.2/lib/netstandard1.3/SharpCompress.dll
create mode 100644 packages/SharpCompress.0.21.1/SharpCompress.0.21.1.nupkg
create mode 100644 packages/SharpCompress.0.21.1/lib/net35/SharpCompress.dll
create mode 100644 packages/SharpCompress.0.21.1/lib/net45/SharpCompress.dll
create mode 100644 packages/SharpCompress.0.21.1/lib/netstandard1.0/SharpCompress.dll
create mode 100644 packages/SharpCompress.0.21.1/lib/netstandard1.3/SharpCompress.dll
create mode 100644 packages/SharpCompress.0.21.1/lib/netstandard2.0/SharpCompress.dll
delete mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.0/System.Runtime.CompilerServices.Unsafe.4.5.0.nupkg
delete mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.0/lib/uap10.0.16300/_._
delete mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.0/ref/uap10.0.16300/_._
delete mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.0/version.txt
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/.signature.p7s (88%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/LICENSE.TXT (100%)
create mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.1/System.Runtime.CompilerServices.Unsafe.4.5.1.nupkg
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/THIRD-PARTY-NOTICES.TXT (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll (73%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0/lib/netstandard2.0 => System.Runtime.CompilerServices.Unsafe.4.5.1/lib/netstandard1.0}/System.Runtime.CompilerServices.Unsafe.dll (74%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0/lib/netstandard1.0 => System.Runtime.CompilerServices.Unsafe.4.5.1/lib/netstandard2.0}/System.Runtime.CompilerServices.Unsafe.dll (74%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll (61%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll (63%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml (100%)
rename packages/{System.Runtime.CompilerServices.Unsafe.4.5.0 => System.Runtime.CompilerServices.Unsafe.4.5.1}/useSharedDesignerContext.txt (100%)
create mode 100644 packages/System.Runtime.CompilerServices.Unsafe.4.5.1/version.txt
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/.signature.p7s
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/LICENSE.TXT
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/System.Threading.Tasks.Extensions.4.5.0.nupkg
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/THIRD-PARTY-NOTICES.TXT
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/netcoreapp2.1/_._
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/netstandard1.0/System.Threading.Tasks.Extensions.dll
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/netstandard1.0/System.Threading.Tasks.Extensions.xml
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/netstandard2.0/System.Threading.Tasks.Extensions.dll
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/netstandard2.0/System.Threading.Tasks.Extensions.xml
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/portable-net45+win8+wp8+wpa81/System.Threading.Tasks.Extensions.dll
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/portable-net45+win8+wp8+wpa81/System.Threading.Tasks.Extensions.xml
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/lib/uap10.0.16300/_._
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/netcoreapp2.1/_._
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/netstandard1.0/System.Threading.Tasks.Extensions.dll
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/netstandard1.0/System.Threading.Tasks.Extensions.xml
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/netstandard2.0/System.Threading.Tasks.Extensions.dll
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/netstandard2.0/System.Threading.Tasks.Extensions.xml
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/ref/uap10.0.16300/_._
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/useSharedDesignerContext.txt
delete mode 100644 packages/System.Threading.Tasks.Extensions.4.5.0/version.txt
diff --git a/BDInfo/BDInfo.csproj b/BDInfo/BDInfo.csproj
index 8c0404c4de..a8f5060e69 100644
--- a/BDInfo/BDInfo.csproj
+++ b/BDInfo/BDInfo.csproj
@@ -34,10 +34,10 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/BDInfo/packages.config b/BDInfo/packages.config
index 76aa4bb8c7..85e552f7ee 100644
--- a/BDInfo/packages.config
+++ b/BDInfo/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj
index 91fb09c058..ea1b43767a 100644
--- a/DvdLib/DvdLib.csproj
+++ b/DvdLib/DvdLib.csproj
@@ -49,10 +49,10 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/DvdLib/packages.config b/DvdLib/packages.config
index 76aa4bb8c7..85e552f7ee 100644
--- a/DvdLib/packages.config
+++ b/DvdLib/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 3bac21a93b..33d2c31aad 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -174,19 +174,19 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
diff --git a/Emby.Dlna/packages.config b/Emby.Dlna/packages.config
index d7821eae0f..b5355baf69 100644
--- a/Emby.Dlna/packages.config
+++ b/Emby.Dlna/packages.config
@@ -1,6 +1,6 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj b/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
index f674e9945a..3e0583e5bb 100644
--- a/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
+++ b/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
@@ -35,13 +35,13 @@
..\packages\ImageMagickSharp.1.0.0.19\lib\net45\ImageMagickSharp.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/Emby.Drawing.ImageMagick/packages.config b/Emby.Drawing.ImageMagick/packages.config
index 57284567b2..46dca35426 100644
--- a/Emby.Drawing.ImageMagick/packages.config
+++ b/Emby.Drawing.ImageMagick/packages.config
@@ -1,6 +1,6 @@
-
-
+
+
\ No newline at end of file
diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
index 9af5d94331..864e8f1844 100644
--- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
+++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
@@ -43,13 +43,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config
index 272298aec8..9756e911d7 100644
--- a/Emby.Drawing.Skia/packages.config
+++ b/Emby.Drawing.Skia/packages.config
@@ -1,6 +1,6 @@
-
-
+
+
\ No newline at end of file
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
index 4b5d7dde4f..725e8d28c8 100644
--- a/Emby.Drawing/Emby.Drawing.csproj
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -41,13 +41,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/Emby.Drawing/packages.config
+++ b/Emby.Drawing/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj
index 92201bfc37..05be07fa92 100644
--- a/Emby.Photos/Emby.Photos.csproj
+++ b/Emby.Photos/Emby.Photos.csproj
@@ -32,13 +32,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
..\ThirdParty\taglib\TagLib.Portable.dll
diff --git a/Emby.Photos/packages.config b/Emby.Photos/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/Emby.Photos/packages.config
+++ b/Emby.Photos/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 8bd4a6e485..8cdcc9c6b5 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1008,7 +1008,7 @@ protected void RegisterResources()
var deviceRepo = new SqliteDeviceRepository(LogManager.GetLogger("DeviceManager"), ServerConfigurationManager, FileSystemManager, JsonSerializer);
deviceRepo.Initialize();
- DeviceManager = new DeviceManager(deviceRepo, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
+ DeviceManager = new DeviceManager(AuthenticationRepository, deviceRepo, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
RegisterSingleInstance(deviceRepo);
RegisterSingleInstance(DeviceManager);
@@ -1065,7 +1065,7 @@ protected void RegisterResources()
RegisterSingleInstance(activityLogRepo);
RegisterSingleInstance(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
- var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager);
+ var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager, UserManager);
RegisterSingleInstance(authContext);
RegisterSingleInstance(new SessionContext(UserManager, authContext, SessionManager));
@@ -1930,6 +1930,7 @@ private bool EnablePlugin(string path)
"mbintros.dll",
"embytv.dll",
"Messenger.dll",
+ "Messages.dll",
"MediaBrowser.Plugins.TvMazeProvider.dll",
"MBBookshelf.dll",
"MediaBrowser.Channels.Adult.YouJizz.dll",
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 4164463bab..00e3e65fc0 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -221,7 +221,7 @@ var createMediaStreamsTableCommand
AddColumn(db, "TypedBaseItems", "ProviderIds", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Images", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ProductionLocations", "Text", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "ThemeSongIds", "Text", existingColumnNames);
+ AddColumn(db, "TypedBaseItems", "ExtraIds", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "TotalBitrate", "INT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ExtraType", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Artists", "Text", existingColumnNames);
@@ -404,7 +404,7 @@ var createMediaStreamsTableCommand
"ProviderIds",
"Images",
"ProductionLocations",
- "ThemeSongIds",
+ "ExtraIds",
"TotalBitrate",
"ExtraType",
"Artists",
@@ -522,7 +522,7 @@ private string GetSaveItemCommandText()
"ProviderIds",
"Images",
"ProductionLocations",
- "ThemeSongIds",
+ "ExtraIds",
"TotalBitrate",
"ExtraType",
"Artists",
@@ -1007,13 +1007,13 @@ private void SaveItem(BaseItem item, BaseItem topParent, string userDataKey, ISt
saveItemStatement.TryBindNull("@ProductionLocations");
}
- if (item.ThemeSongIds.Length > 0)
+ if (item.ExtraIds.Length > 0)
{
- saveItemStatement.TryBind("@ThemeSongIds", string.Join("|", item.ThemeSongIds.ToArray()));
+ saveItemStatement.TryBind("@ExtraIds", string.Join("|", item.ExtraIds.ToArray()));
}
else
{
- saveItemStatement.TryBindNull("@ThemeSongIds");
+ saveItemStatement.TryBindNull("@ExtraIds");
}
saveItemStatement.TryBind("@TotalBitrate", item.TotalBitrate);
@@ -1864,11 +1864,11 @@ private BaseItem GetItem(IReadOnlyList reader, InternalItemsQue
index++;
}
- if (HasField(query, ItemFields.ThemeSongIds))
+ if (HasField(query, ItemFields.ExtraIds))
{
if (!reader.IsDBNull(index))
{
- item.ThemeSongIds = SplitToGuids(reader.GetString(index));
+ item.ExtraIds = SplitToGuids(reader.GetString(index));
}
index++;
}
@@ -2230,7 +2230,7 @@ private bool HasField(InternalItemsQuery query, ItemFields name)
case ItemFields.Taglines:
case ItemFields.SortName:
case ItemFields.Studios:
- case ItemFields.ThemeSongIds:
+ case ItemFields.ExtraIds:
case ItemFields.DateCreated:
case ItemFields.Overview:
case ItemFields.Genres:
@@ -2534,11 +2534,7 @@ private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] star
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
{
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
- {
- excludeIds.AddRange(hasTrailers.GetTrailerIds());
- }
+ excludeIds.AddRange(item.ExtraIds);
}
query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count);
@@ -3436,12 +3432,42 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
{
//whereClauses.Add("(UserId is null or UserId=@UserId)");
}
- if (query.MinWidth.HasValue)
+
+ var minWidth = query.MinWidth;
+ var maxWidth = query.MaxWidth;
+
+ if (query.IsHD.HasValue)
+ {
+ var threshold = 1200;
+ if (query.IsHD.Value)
+ {
+ minWidth = threshold;
+ }
+ else
+ {
+ maxWidth = threshold - 1;
+ }
+ }
+
+ if (query.Is4K.HasValue)
+ {
+ var threshold = 3800;
+ if (query.Is4K.Value)
+ {
+ minWidth = threshold;
+ }
+ else
+ {
+ maxWidth = threshold - 1;
+ }
+ }
+
+ if (minWidth.HasValue)
{
whereClauses.Add("Width>=@MinWidth");
if (statement != null)
{
- statement.TryBind("@MinWidth", query.MinWidth);
+ statement.TryBind("@MinWidth", minWidth);
}
}
if (query.MinHeight.HasValue)
@@ -3452,12 +3478,12 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
statement.TryBind("@MinHeight", query.MinHeight);
}
}
- if (query.MaxWidth.HasValue)
+ if (maxWidth.HasValue)
{
whereClauses.Add("Width<=@MaxWidth");
if (statement != null)
{
- statement.TryBind("@MaxWidth", query.MaxWidth);
+ statement.TryBind("@MaxWidth", maxWidth);
}
}
if (query.MaxHeight.HasValue)
@@ -4079,6 +4105,25 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
whereClauses.Add(clause);
}
+ if (query.AlbumArtistIds.Length > 0)
+ {
+ var clauses = new List();
+ var index = 0;
+ foreach (var artistId in query.AlbumArtistIds)
+ {
+ var paramName = "@ArtistIds" + index;
+
+ clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=1)");
+ if (statement != null)
+ {
+ statement.TryBind(paramName, artistId.ToGuidBlob());
+ }
+ index++;
+ }
+ var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+ whereClauses.Add(clause);
+ }
+
if (query.AlbumIds.Length > 0)
{
var clauses = new List();
@@ -4253,6 +4298,18 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
}
}
+ if (query.HasOfficialRating.HasValue)
+ {
+ if (query.HasOfficialRating.Value)
+ {
+ whereClauses.Add("(OfficialRating not null AND OfficialRating<>'')");
+ }
+ else
+ {
+ whereClauses.Add("(OfficialRating is null OR OfficialRating='')");
+ }
+ }
+
if (query.HasOverview.HasValue)
{
if (query.HasOverview.Value)
@@ -4265,6 +4322,18 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
}
}
+ if (query.HasOwnerId.HasValue)
+ {
+ if (query.HasOwnerId.Value)
+ {
+ whereClauses.Add("OwnerId not null");
+ }
+ else
+ {
+ whereClauses.Add("OwnerId is null");
+ }
+ }
+
if (!string.IsNullOrWhiteSpace(query.HasNoAudioTrackWithLanguage))
{
whereClauses.Add("((select language from MediaStreams where MediaStreams.ItemId=A.Guid and MediaStreams.StreamType='Audio' and MediaStreams.Language=@HasNoAudioTrackWithLanguage limit 1) is null)");
@@ -4301,6 +4370,18 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
}
}
+ if (query.HasSubtitles.HasValue)
+ {
+ if (query.HasSubtitles.Value)
+ {
+ whereClauses.Add("((select type from MediaStreams where MediaStreams.ItemId=A.Guid and MediaStreams.StreamType='Subtitle' limit 1) not null)");
+ }
+ else
+ {
+ whereClauses.Add("((select type from MediaStreams where MediaStreams.ItemId=A.Guid and MediaStreams.StreamType='Subtitle' limit 1) is null)");
+ }
+ }
+
if (query.HasChapterImages.HasValue)
{
if (query.HasChapterImages.Value)
@@ -4453,7 +4534,40 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
break;
}
- whereClauses.Add(string.Join(" AND ", excludeIds.ToArray()));
+ if (excludeIds.Count > 0)
+ {
+ whereClauses.Add(string.Join(" AND ", excludeIds.ToArray()));
+ }
+ }
+
+ if (query.HasAnyProviderId.Count > 0)
+ {
+ var hasProviderIds = new List();
+
+ var index = 0;
+ foreach (var pair in query.HasAnyProviderId)
+ {
+ if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ var paramName = "@HasAnyProviderId" + index;
+ //hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
+ hasProviderIds.Add("ProviderIds like " + paramName + "");
+ if (statement != null)
+ {
+ statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
+ }
+ index++;
+
+ break;
+ }
+
+ if (hasProviderIds.Count > 0)
+ {
+ whereClauses.Add("(" + string.Join(" OR ", hasProviderIds.ToArray()) + ")");
+ }
}
if (query.HasImdbId.HasValue)
@@ -4470,17 +4584,6 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
{
whereClauses.Add("ProviderIds like '%tvdb=%'");
}
- if (query.HasThemeSong.HasValue)
- {
- if (query.HasThemeSong.Value)
- {
- whereClauses.Add("ThemeSongIds not null");
- }
- else
- {
- whereClauses.Add("ThemeSongIds is null");
- }
- }
var includedItemByNameTypes = GetItemByNameTypesInQuery(query).SelectMany(MapIncludeItemTypes).ToList();
var enableItemsByName = (query.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
@@ -4590,6 +4693,102 @@ private List GetWhereClauses(InternalItemsQuery query, IStatement statem
whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + tagValuesList + ")) is null)");
}
+ if (query.SeriesStatuses.Length > 0)
+ {
+ var statuses = new List();
+
+ foreach (var seriesStatus in query.SeriesStatuses)
+ {
+ statuses.Add("data like '%" + seriesStatus + "%'");
+ }
+
+ whereClauses.Add("(" + string.Join(" OR ", statuses.ToArray()) + ")");
+ }
+
+ if (query.VideoTypes.Length > 0)
+ {
+ var videoTypes = new List();
+
+ foreach (var videoType in query.VideoTypes)
+ {
+ videoTypes.Add("data like '%" + videoType + "%'");
+ }
+
+ whereClauses.Add("(" + string.Join(" OR ", videoTypes.ToArray()) + ")");
+ }
+
+ if (query.Is3D.HasValue)
+ {
+ if (query.Is3D.Value)
+ {
+ whereClauses.Add("data like '%Video3DFormat%'");
+ }
+ else
+ {
+ whereClauses.Add("data not like '%Video3DFormat%'");
+ }
+ }
+
+ if (query.IsPlaceHolder.HasValue)
+ {
+ if (query.IsPlaceHolder.Value)
+ {
+ whereClauses.Add("data like '\"IsPlaceHolder\":true");
+ }
+ else
+ {
+ whereClauses.Add("data not like '\"IsPlaceHolder\":true");
+ }
+ }
+
+ if (query.HasSpecialFeature.HasValue)
+ {
+ if (query.HasSpecialFeature.Value)
+ {
+ whereClauses.Add("(data not like '%\"ExtraIds\":[]%' and data like '%ExtraIds%')");
+ }
+ else
+ {
+ whereClauses.Add("(data like '%\"ExtraIds\":[]%' or data not like '%ExtraIds%')");
+ }
+ }
+
+ if (query.HasTrailer.HasValue)
+ {
+ if (query.HasTrailer.Value)
+ {
+ whereClauses.Add("((data not like '%\"LocalTrailerIds\":[]%' and data like '%LocalTrailerIds%') or (data not like '%\"RemoteTrailerIds\":[]%' and data like '%RemoteTrailerIds%') or (data not like '%\"RemoteTrailers\":[]%' and data like '%RemoteTrailers%'))");
+ }
+ else
+ {
+ whereClauses.Add("((data like '%\"LocalTrailerIds\":[]%' or data not like '%LocalTrailerIds%') and (data like '%\"RemoteTrailerIds\":[]%' or data not like '%RemoteTrailerIds%') and (data like '%\"RemoteTrailers\":[]%' or data not like '%RemoteTrailers%'))");
+ }
+ }
+
+ if (query.HasThemeSong.HasValue)
+ {
+ if (query.HasThemeSong.Value)
+ {
+ whereClauses.Add("(data not like '%\"ExtraIds\":[]%' and data like '%ExtraIds%')");
+ }
+ else
+ {
+ whereClauses.Add("(data like '%\"ExtraIds\":[]%' or data not like '%ExtraIds%')");
+ }
+ }
+
+ if (query.HasThemeVideo.HasValue)
+ {
+ if (query.HasThemeVideo.Value)
+ {
+ whereClauses.Add("(data not like '%\"ExtraIds\":[]%' and data like '%ExtraIds%')");
+ }
+ else
+ {
+ whereClauses.Add("(data like '%\"ExtraIds\":[]%' or data not like '%ExtraIds%')");
+ }
+ }
+
return whereClauses;
}
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index 882ebc3b3a..93af05bdbb 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -23,6 +23,7 @@
using MediaBrowser.Model.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Controller.Security;
namespace Emby.Server.Implementations.Devices
{
@@ -38,14 +39,11 @@ public class DeviceManager : IDeviceManager
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localizationManager;
- public event EventHandler> CameraImageUploaded;
+ private readonly IAuthenticationRepository _authRepo;
- ///
- /// Occurs when [device options updated].
- ///
- public event EventHandler> DeviceOptionsUpdated;
+ public event EventHandler> CameraImageUploaded;
- public DeviceManager(IDeviceRepository repo, ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IServerConfigurationManager config, ILogger logger, INetworkManager network)
+ public DeviceManager(IAuthenticationRepository authRepo, IDeviceRepository repo, ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IServerConfigurationManager config, ILogger logger, INetworkManager network)
{
_repo = repo;
_userManager = userManager;
@@ -56,68 +54,7 @@ public DeviceManager(IDeviceRepository repo, ILibraryManager libraryManager, ILo
_network = network;
_libraryManager = libraryManager;
_localizationManager = localizationManager;
- }
-
- public DeviceInfo RegisterDevice(string reportedId, string name, string appName, string appVersion, string usedByUserId, string usedByUserName)
- {
- if (string.IsNullOrEmpty(reportedId))
- {
- throw new ArgumentNullException("reportedId");
- }
-
- var save = false;
- var device = GetDevice(reportedId);
-
- if (device == null)
- {
- device = new DeviceInfo
- {
- Id = reportedId
- };
- save = true;
- }
-
- if (!string.Equals(device.ReportedName, name, StringComparison.Ordinal))
- {
- device.ReportedName = name;
- save = true;
- }
- if (!string.Equals(device.AppName, appName, StringComparison.Ordinal))
- {
- device.AppName = appName;
- save = true;
- }
- if (!string.Equals(device.AppVersion, appVersion, StringComparison.Ordinal))
- {
- device.AppVersion = appVersion;
- save = true;
- }
-
- if (!string.IsNullOrEmpty(usedByUserId))
- {
- if (!string.Equals(device.LastUserId, usedByUserId, StringComparison.Ordinal) ||
- !string.Equals(device.LastUserName, usedByUserName, StringComparison.Ordinal))
- {
- device.LastUserId = usedByUserId;
- device.LastUserName = usedByUserName;
- save = true;
- }
- }
-
- var displayName = string.IsNullOrWhiteSpace(device.CustomName) ? device.ReportedName : device.CustomName;
- if (!string.Equals(device.Name, displayName, StringComparison.Ordinal))
- {
- device.Name = displayName;
- save = true;
- }
-
- if (save)
- {
- device.DateLastModified = DateTime.UtcNow;
- _repo.SaveDevice(device);
- }
-
- return device;
+ _authRepo = authRepo;
}
public void SaveCapabilities(string reportedId, ClientCapabilities capabilities)
@@ -127,44 +64,53 @@ public void SaveCapabilities(string reportedId, ClientCapabilities capabilities)
public ClientCapabilities GetCapabilities(string reportedId)
{
- return _repo.GetCapabilities(reportedId);
+ return _repo.GetCapabilities(reportedId) ?? new ClientCapabilities();
}
public DeviceInfo GetDevice(string id)
{
- return _repo.GetDevice(id);
+ return GetDevice(id, true);
}
- public QueryResult GetDevices(DeviceQuery query)
+ private DeviceInfo GetDevice(string id, bool includeCapabilities)
{
- IEnumerable devices = _repo.GetDevices();
+ var session = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ DeviceId = id
- if (query.SupportsSync.HasValue)
+ }).Items.FirstOrDefault();
+
+ var device = session == null ? null : ToDeviceInfo(session);
+
+ return device;
+ }
+
+ public QueryResult GetDevices(DeviceQuery query)
+ {
+ var sessions = _authRepo.Get(new AuthenticationInfoQuery
{
- var val = query.SupportsSync.Value;
+ //UserId = query.UserId
+ IsActive = true,
+ HasUser = true
- devices = devices.Where(i => i.Capabilities.SupportsSync == val);
- }
+ }).Items;
- if (query.SupportsPersistentIdentifier.HasValue)
+ if (query.SupportsSync.HasValue)
{
- var val = query.SupportsPersistentIdentifier.Value;
+ var val = query.SupportsSync.Value;
- devices = devices.Where(i =>
- {
- var deviceVal = i.Capabilities.SupportsPersistentIdentifier;
- return deviceVal == val;
- });
+ sessions = sessions.Where(i => GetCapabilities(i.DeviceId).SupportsSync == val).ToArray();
}
if (!query.UserId.Equals(Guid.Empty))
{
var user = _userManager.GetUserById(query.UserId);
- devices = devices.Where(i => CanAccessDevice(user, i.Id));
+ sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId)).ToArray();
}
- var array = devices.ToArray();
+ var array = sessions.Select(ToDeviceInfo).ToArray();
+
return new QueryResult
{
Items = array,
@@ -172,9 +118,18 @@ public QueryResult GetDevices(DeviceQuery query)
};
}
- public void DeleteDevice(string id)
+ private DeviceInfo ToDeviceInfo(AuthenticationInfo authInfo)
{
- _repo.DeleteDevice(id);
+ return new DeviceInfo
+ {
+ AppName = authInfo.AppName,
+ AppVersion = authInfo.AppVersion,
+ Id = authInfo.DeviceId,
+ LastUserId = authInfo.UserId,
+ LastUserName = authInfo.UserName,
+ Name = authInfo.DeviceName,
+ DateLastActivity = authInfo.DateLastActivity
+ };
}
public ContentUploadHistory GetCameraUploadHistory(string deviceId)
@@ -184,7 +139,7 @@ public ContentUploadHistory GetCameraUploadHistory(string deviceId)
public async Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file)
{
- var device = GetDevice(deviceId);
+ var device = GetDevice(deviceId, false);
var uploadPathInfo = GetUploadPath(device);
var path = uploadPathInfo.Item1;
@@ -264,11 +219,6 @@ internal Task EnsureLibraryFolder(string path, string name)
private Tuple GetUploadPath(DeviceInfo device)
{
- if (!string.IsNullOrWhiteSpace(device.CameraUploadPath))
- {
- return new Tuple(device.CameraUploadPath, device.CameraUploadPath, _fileSystem.GetDirectoryName(device.CameraUploadPath));
- }
-
var config = _config.GetUploadOptions();
var path = config.CameraUploadPath;
@@ -305,20 +255,6 @@ private string DefaultCameraUploadsPath
get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); }
}
- public void UpdateDeviceInfo(string id, DeviceOptions options)
- {
- var device = GetDevice(id);
-
- device.CustomName = options.CustomName;
- device.CameraUploadPath = options.CameraUploadPath;
-
- device.Name = string.IsNullOrWhiteSpace(device.CustomName) ? device.ReportedName : device.CustomName;
-
- _repo.SaveDevice(device);
-
- EventHelper.FireEventIfNotNull(DeviceOptionsUpdated, this, new GenericEventArgs(device), _logger);
- }
-
public bool CanAccessDevice(User user, string deviceId)
{
if (user == null)
diff --git a/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs b/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
index d80b11d6f7..408c41a25b 100644
--- a/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
+++ b/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
@@ -22,10 +22,13 @@ public class SqliteDeviceRepository : BaseSqliteRepository, IDeviceRepository
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
protected IFileSystem FileSystem { get; private set; }
- private readonly object _syncLock = new object();
+ private readonly object _cameraUploadSyncLock = new object();
+ private readonly object _capabilitiesSyncLock = new object();
private readonly IJsonSerializer _json;
private IServerApplicationPaths _appPaths;
+ private bool _enableDatabase;
+
public SqliteDeviceRepository(ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IJsonSerializer json)
: base(logger)
{
@@ -35,325 +38,108 @@ public SqliteDeviceRepository(ILogger logger, IServerConfigurationManager config
FileSystem = fileSystem;
_json = json;
_appPaths = appPaths;
+
}
public void Initialize()
{
- try
- {
- InitializeInternal();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
+ _enableDatabase = FileSystem.FileExists(DbFilePath);
- FileSystem.DeleteFile(DbFilePath);
-
- InitializeInternal();
- }
- }
-
- private void InitializeInternal()
- {
- using (var connection = CreateConnection())
+ if (_enableDatabase)
{
- RunDefaultInitialization(connection);
+ try
+ {
+ using (var connection = CreateConnection())
+ {
+ RunDefaultInitialization(connection);
- string[] queries = {
+ string[] queries = {
"create table if not exists Devices (Id TEXT PRIMARY KEY, Name TEXT NOT NULL, ReportedName TEXT NOT NULL, CustomName TEXT, CameraUploadPath TEXT, LastUserName TEXT, AppName TEXT NOT NULL, AppVersion TEXT NOT NULL, LastUserId TEXT, DateLastModified DATETIME NOT NULL, Capabilities TEXT NOT NULL)",
"create index if not exists idx_id on Devices(Id)"
};
- connection.RunQueries(queries);
-
- MigrateDevices();
- }
- }
-
- private void MigrateDevices()
- {
- List files;
- try
- {
- files = FileSystem
- .GetFilePaths(GetDevicesPath(), true)
- .Where(i => string.Equals(Path.GetFileName(i), "device.json", StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
- catch (IOException)
- {
- return;
- }
-
- foreach (var file in files)
- {
- try
- {
- var device = _json.DeserializeFromFile(file);
-
- device.Name = string.IsNullOrWhiteSpace(device.CustomName) ? device.ReportedName : device.CustomName;
-
- SaveDevice(device);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error reading {0}", ex, file);
- }
- finally
- {
- try
- {
- FileSystem.DeleteFile(file);
- }
- catch (IOException)
- {
- try
- {
- FileSystem.MoveFile(file, Path.ChangeExtension(file, ".old"));
- }
- catch (IOException)
- {
- }
+ connection.RunQueries(queries);
}
}
- }
- }
-
- private const string BaseSelectText = "select Id, Name, ReportedName, CustomName, CameraUploadPath, LastUserName, AppName, AppVersion, LastUserId, DateLastModified, Capabilities from Devices";
-
- public void SaveCapabilities(string deviceId, ClientCapabilities capabilities)
- {
- using (WriteLock.Write())
- {
- using (var connection = CreateConnection())
+ catch (Exception ex)
{
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("update devices set Capabilities=@Capabilities where Id=@Id"))
- {
- statement.TryBind("@Id", deviceId);
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
- if (capabilities == null)
- {
- statement.TryBindNull("@Capabilities");
- }
- else
- {
- statement.TryBind("@Capabilities", _json.SerializeToString(capabilities));
- }
+ FileSystem.DeleteFile(DbFilePath);
- statement.MoveNext();
- }
- }, TransactionMode);
+ _enableDatabase = false;
}
}
}
- public void SaveDevice(DeviceInfo entry)
+ public void SaveCapabilities(string deviceId, ClientCapabilities capabilities)
{
- if (entry == null)
- {
- throw new ArgumentNullException("entry");
- }
+ var path = Path.Combine(GetDevicePath(deviceId), "capabilities.json");
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
- using (WriteLock.Write())
+ lock (_capabilitiesSyncLock)
{
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("replace into Devices (Id, Name, ReportedName, CustomName, CameraUploadPath, LastUserName, AppName, AppVersion, LastUserId, DateLastModified, Capabilities) values (@Id, @Name, @ReportedName, @CustomName, @CameraUploadPath, @LastUserName, @AppName, @AppVersion, @LastUserId, @DateLastModified, @Capabilities)"))
- {
- statement.TryBind("@Id", entry.Id);
- statement.TryBind("@Name", entry.Name);
- statement.TryBind("@ReportedName", entry.ReportedName);
- statement.TryBind("@CustomName", entry.CustomName);
- statement.TryBind("@CameraUploadPath", entry.CameraUploadPath);
- statement.TryBind("@LastUserId", entry.LastUserId);
- statement.TryBind("@LastUserName", entry.LastUserName);
- statement.TryBind("@AppName", entry.AppName);
- statement.TryBind("@AppVersion", entry.AppVersion);
- statement.TryBind("@DateLastModified", entry.DateLastModified);
-
- if (entry.Capabilities == null)
- {
- statement.TryBindNull("@Capabilities");
- }
- else
- {
- statement.TryBind("@Capabilities", _json.SerializeToString(entry.Capabilities));
- }
+ _capabilitiesCache[deviceId] = capabilities;
- statement.MoveNext();
- }
- }, TransactionMode);
- }
+ _json.SerializeToFile(capabilities, path);
}
}
- public DeviceInfo GetDevice(string id)
+ private Dictionary _capabilitiesCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ public ClientCapabilities GetCapabilities(string id)
{
- using (WriteLock.Read())
+ lock (_capabilitiesSyncLock)
{
- using (var connection = CreateConnection(true))
+ ClientCapabilities result;
+ if (_capabilitiesCache.TryGetValue(id, out result))
{
- var statementTexts = new List();
- statementTexts.Add(BaseSelectText + " where Id=@Id");
-
- return connection.RunInTransaction(db =>
- {
- var statements = PrepareAllSafe(db, statementTexts).ToList();
-
- using (var statement = statements[0])
- {
- statement.TryBind("@Id", id);
-
- foreach (var row in statement.ExecuteQuery())
- {
- return GetEntry(row);
- }
- }
-
- return null;
-
- }, ReadTransactionMode);
+ return result;
}
- }
- }
- public List GetDevices()
- {
- using (WriteLock.Read())
- {
- using (var connection = CreateConnection(true))
+ var path = Path.Combine(GetDevicePath(id), "capabilities.json");
+ try
+ {
+ return _json.DeserializeFromFile(path);
+ }
+ catch
{
- var statementTexts = new List();
- statementTexts.Add(BaseSelectText + " order by DateLastModified desc");
-
- return connection.RunInTransaction(db =>
- {
- var list = new List();
-
- var statements = PrepareAllSafe(db, statementTexts).ToList();
-
- using (var statement = statements[0])
- {
- foreach (var row in statement.ExecuteQuery())
- {
- list.Add(GetEntry(row));
- }
- }
-
- return list;
-
- }, ReadTransactionMode);
}
}
- }
- public ClientCapabilities GetCapabilities(string id)
- {
- using (WriteLock.Read())
+ if (_enableDatabase)
{
- using (var connection = CreateConnection(true))
+ using (WriteLock.Read())
{
- var statementTexts = new List();
- statementTexts.Add("Select Capabilities from Devices where Id=@Id");
-
- return connection.RunInTransaction(db =>
+ using (var connection = CreateConnection(true))
{
- var statements = PrepareAllSafe(db, statementTexts).ToList();
+ var statementTexts = new List();
+ statementTexts.Add("Select Capabilities from Devices where Id=@Id");
- using (var statement = statements[0])
+ return connection.RunInTransaction(db =>
{
- statement.TryBind("@Id", id);
+ var statements = PrepareAllSafe(db, statementTexts).ToList();
- foreach (var row in statement.ExecuteQuery())
+ using (var statement = statements[0])
{
- if (row[0].SQLiteType != SQLiteType.Null)
+ statement.TryBind("@Id", id);
+
+ foreach (var row in statement.ExecuteQuery())
{
- return _json.DeserializeFromString(row.GetString(0));
+ if (row[0].SQLiteType != SQLiteType.Null)
+ {
+ return _json.DeserializeFromString(row.GetString(0));
+ }
}
- }
- }
- return null;
+ return new ClientCapabilities();
+ }
- }, ReadTransactionMode);
+ }, ReadTransactionMode);
+ }
}
}
- }
-
- private DeviceInfo GetEntry(IReadOnlyList reader)
- {
- var index = 0;
-
- var info = new DeviceInfo
- {
- Id = reader.GetString(index)
- };
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Name = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.ReportedName = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.CustomName = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.CameraUploadPath = reader.GetString(index);
- }
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.LastUserName = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.AppName = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.AppVersion = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.LastUserId = reader.GetString(index);
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.DateLastModified = reader[index].ReadDateTime();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Capabilities = _json.DeserializeFromString(reader.GetString(index));
- }
-
- return info;
+ return new ClientCapabilities();
}
private string GetDevicesPath()
@@ -370,7 +156,7 @@ public ContentUploadHistory GetCameraUploadHistory(string deviceId)
{
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
- lock (_syncLock)
+ lock (_cameraUploadSyncLock)
{
try
{
@@ -391,7 +177,7 @@ public void AddCameraUpload(string deviceId, LocalFileInfo file)
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
- lock (_syncLock)
+ lock (_cameraUploadSyncLock)
{
ContentUploadHistory history;
@@ -416,37 +202,5 @@ public void AddCameraUpload(string deviceId, LocalFileInfo file)
_json.SerializeToFile(history, path);
}
}
-
- public void DeleteDevice(string id)
- {
- using (WriteLock.Write())
- {
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("delete from devices where Id=@Id"))
- {
- statement.TryBind("@Id", id);
-
- statement.MoveNext();
- }
- }, TransactionMode);
- }
- }
-
- var path = GetDevicePath(id);
-
- lock (_syncLock)
- {
- try
- {
- FileSystem.DeleteDirectory(path, true);
- }
- catch (IOException)
- {
- }
- }
- }
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index e0f8fc11a3..5e67a44158 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -841,12 +841,6 @@ private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, D
dto.CriticRating = item.CriticRating;
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
- {
- dto.LocalTrailerCount = hasTrailers.GetTrailerIds().Count;
- }
-
var hasDisplayOrder = item as IHasDisplayOrder;
if (hasDisplayOrder != null)
{
@@ -861,9 +855,7 @@ private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, D
if (fields.Contains(ItemFields.RemoteTrailers))
{
- dto.RemoteTrailers = hasTrailers != null ?
- hasTrailers.RemoteTrailers :
- new MediaUrl[] { };
+ dto.RemoteTrailers = item.RemoteTrailers;
}
dto.Name = item.Name;
@@ -1139,15 +1131,26 @@ private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, D
}
}
- var hasSpecialFeatures = item as IHasSpecialFeatures;
- if (hasSpecialFeatures != null)
+ BaseItem[] allExtras = null;
+
+ if (fields.Contains(ItemFields.SpecialFeatureCount))
{
- var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Length;
+ if (allExtras == null)
+ {
+ allExtras = item.GetExtras().ToArray();
+ }
+
+ dto.SpecialFeatureCount = allExtras.Count(i => i.ExtraType.HasValue && BaseItem.DisplayExtraTypes.Contains(i.ExtraType.Value));
+ }
- if (specialFeatureCount > 0)
+ if (fields.Contains(ItemFields.LocalTrailerCount))
+ {
+ if (allExtras == null)
{
- dto.SpecialFeatureCount = specialFeatureCount;
+ allExtras = item.GetExtras().ToArray();
}
+
+ dto.LocalTrailerCount = allExtras.Count(i => i.ExtraType.HasValue && i.ExtraType.Value == ExtraType.Trailer);
}
// Add EpisodeInfo
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index a715782485..47cf2df8c5 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -338,7 +338,6 @@
-
@@ -605,7 +604,7 @@
Mono.Nat
- ..\packages\MediaBrowser.Naming.1.1.5-beta\lib\netstandard2.0\Emby.Naming.dll
+ ..\packages\MediaBrowser.Naming.1.1.6-beta\lib\netstandard2.0\Emby.Naming.dll
..\ThirdParty\emby\Emby.Server.MediaEncoding.dll
@@ -614,13 +613,13 @@
..\packages\Emby.XmlTv.1.0.14\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
@@ -630,12 +629,11 @@
..\packages\PlaylistsNET.1.0.0\lib\netstandard1.4\PlaylistsNET.dll
-
- ..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll
- True
+
+ ..\packages\ServiceStack.Text.5.1.0\lib\net45\ServiceStack.Text.dll
-
- ..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll
+
+ ..\packages\SharpCompress.0.21.1\lib\net45\SharpCompress.dll
..\packages\SimpleInjector.4.3.0\lib\net45\SimpleInjector.dll
@@ -644,6 +642,9 @@
..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll
True
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
..\packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll
True
@@ -741,9 +742,6 @@
True
True
-
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
-
..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll
True
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
index fa6fbc0bd2..09157c1bf8 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -64,9 +64,7 @@ private void ValidateUser(IRequest request, IAuthenticationAttributes authAttrib
throw new SecurityException("Operation not found.");
}
- var user = auth.UserId.Equals(Guid.Empty)
- ? null
- : UserManager.GetUserById(auth.UserId);
+ var user = auth.User;
if (user == null & !auth.UserId.Equals(Guid.Empty))
{
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 5693b8ce0a..c0d520a92a 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -6,6 +6,7 @@
using MediaBrowser.Model.Services;
using System.Linq;
using System.Threading;
+using MediaBrowser.Controller.Library;
namespace Emby.Server.Implementations.HttpServer.Security
{
@@ -13,11 +14,13 @@ public class AuthorizationContext : IAuthorizationContext
{
private readonly IAuthenticationRepository _authRepo;
private readonly IConnectManager _connectManager;
+ private readonly IUserManager _userManager;
- public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager)
+ public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager, IUserManager userManager)
{
_authRepo = authRepo;
_connectManager = connectManager;
+ _userManager = userManager;
}
public AuthorizationInfo GetAuthorizationInfo(object requestContext)
@@ -94,8 +97,6 @@ private AuthorizationInfo GetAuthorization(IRequest httpReq)
if (tokenInfo != null)
{
- info.UserId = tokenInfo.UserId;
-
var updateToken = false;
// TODO: Remove these checks for IsNullOrWhiteSpace
@@ -109,15 +110,21 @@ private AuthorizationInfo GetAuthorization(IRequest httpReq)
info.DeviceId = tokenInfo.DeviceId;
}
+ // Temporary. TODO - allow clients to specify that the token has been shared with a casting device
+ var allowTokenInfoUpdate = info.Client == null || info.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1;
if (string.IsNullOrWhiteSpace(info.Device))
{
info.Device = tokenInfo.DeviceName;
}
+
else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase))
{
- updateToken = true;
- tokenInfo.DeviceName = info.Device;
+ if (allowTokenInfoUpdate)
+ {
+ updateToken = true;
+ tokenInfo.DeviceName = info.Device;
+ }
}
if (string.IsNullOrWhiteSpace(info.Version))
@@ -126,8 +133,28 @@ private AuthorizationInfo GetAuthorization(IRequest httpReq)
}
else if (!string.Equals(info.Version, tokenInfo.AppVersion, StringComparison.OrdinalIgnoreCase))
{
+ if (allowTokenInfoUpdate)
+ {
+ updateToken = true;
+ tokenInfo.AppVersion = info.Version;
+ }
+ }
+
+ if ((DateTime.UtcNow - tokenInfo.DateLastActivity).TotalMinutes > 3)
+ {
+ tokenInfo.DateLastActivity = DateTime.UtcNow;
updateToken = true;
- tokenInfo.AppVersion = info.Version;
+ }
+
+ if (!tokenInfo.UserId.Equals(Guid.Empty))
+ {
+ info.User = _userManager.GetUserById(tokenInfo.UserId);
+
+ if (info.User != null && !string.Equals(info.User.Name, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
+ {
+ tokenInfo.UserName = info.User.Name;
+ updateToken = true;
+ }
}
if (updateToken)
@@ -137,11 +164,7 @@ private AuthorizationInfo GetAuthorization(IRequest httpReq)
}
else
{
- var user = _connectManager.GetUserFromExchangeToken(token);
- if (user != null)
- {
- info.UserId = user.Id;
- }
+ info.User = _connectManager.GetUserFromExchangeToken(token);
}
httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo;
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
index b25daf554d..a919ce0083 100644
--- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
@@ -26,7 +26,7 @@ public SessionInfo GetSession(IRequest requestContext)
{
var authorization = _authContext.GetAuthorizationInfo(requestContext);
- var user = authorization.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(authorization.UserId);
+ var user = authorization.User;
return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user);
}
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 7978b82548..66d7802c6f 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -30,7 +30,7 @@ public class ManagedFileSystem : IFileSystem
private string _defaultDirectory;
- public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string defaultDirectory, string tempPath)
+ public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string defaultDirectory, string tempPath, bool enableSeparateFileAndDirectoryQueries)
{
Logger = logger;
_supportsAsyncFileStreams = true;
@@ -38,10 +38,8 @@ public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, strin
_environmentInfo = environmentInfo;
_defaultDirectory = defaultDirectory;
- // On Linux, this needs to be true or symbolic links are ignored
- // TODO: See if still needed under .NET Core
- EnableSeparateFileAndDirectoryQueries = environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
- environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX;
+ // On Linux with mono, this needs to be true or symbolic links are ignored
+ EnableSeparateFileAndDirectoryQueries = enableSeparateFileAndDirectoryQueries;
SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows);
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index fabe0c434e..31af9370c7 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -2593,11 +2593,10 @@ public IEnumerable FindTrailers(BaseItem owner, List
{
video = dbItem;
}
- else
- {
- // item is new
- video.ExtraType = ExtraType.Trailer;
- }
+
+ video.ParentId = Guid.Empty;
+ video.OwnerId = owner.Id;
+ video.ExtraType = ExtraType.Trailer;
video.TrailerTypes = new [] { TrailerType.LocalTrailer };
return video;
@@ -2640,6 +2639,9 @@ public IEnumerable FindExtras(BaseItem owner, List fi
video = dbItem;
}
+ video.ParentId = Guid.Empty;
+ video.OwnerId = owner.Id;
+
SetExtraTypeFromFilename(video);
return video;
diff --git a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
deleted file mode 100644
index d36a52696b..0000000000
--- a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-
-namespace Emby.Server.Implementations.Library
-{
- public class LocalTrailerPostScanTask : ILibraryPostScanTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IChannelManager _channelManager;
-
- public LocalTrailerPostScanTask(ILibraryManager libraryManager, IChannelManager channelManager)
- {
- _libraryManager = libraryManager;
- _channelManager = channelManager;
- }
-
- public Task Run(IProgress progress, CancellationToken cancellationToken)
- {
- var items = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name },
- Recursive = true,
- DtoOptions = new DtoOptions(true)
-
- }).OfType().ToList();
-
- var trailerTypes = Enum.GetNames(typeof(TrailerType))
- .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true))
- .Except(new[] { TrailerType.LocalTrailer })
- .ToArray();
-
- var trailers = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Trailer).Name },
- TrailerTypes = trailerTypes,
- Recursive = true,
- DtoOptions = new DtoOptions(false)
- });
-
- var numComplete = 0;
-
- foreach (var item in items)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- AssignTrailers(item, trailers);
-
- numComplete++;
- double percent = numComplete;
- percent /= items.Count;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
-
- return Task.CompletedTask;
- }
-
- private void AssignTrailers(IHasTrailers item, IEnumerable channelTrailers)
- {
- if (item is Game)
- {
- return;
- }
-
- var imdbId = item.GetProviderId(MetadataProviders.Imdb);
- var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
-
- var trailers = channelTrailers.Where(i =>
- {
- if (!string.IsNullOrEmpty(imdbId) &&
- string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (!string.IsNullOrEmpty(tmdbId) &&
- string.Equals(tmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- return false;
- });
-
- var trailerIds = trailers.Select(i => i.Id)
- .ToArray();
-
- if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
- {
- item.RemoteTrailerIds = trailerIds;
-
- var baseItem = (BaseItem)item;
- baseItem.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index f2578348cc..2f632d3843 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -230,13 +230,15 @@ public bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPosi
{
var playedToCompletion = false;
- var positionTicks = reportedPositionTicks ?? item.RunTimeTicks ?? 0;
- var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
+ var runtimeTicks = item.GetRunTimeTicksForPlayState();
+
+ var positionTicks = reportedPositionTicks ?? runtimeTicks;
+ var hasRuntime = runtimeTicks > 0;
// If a position has been reported, and if we know the duration
if (positionTicks > 0 && hasRuntime)
{
- var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
+ var pctIn = Decimal.Divide(positionTicks, runtimeTicks) * 100;
// Don't track in very beginning
if (pctIn < _config.Configuration.MinResumePct)
@@ -245,7 +247,7 @@ public bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPosi
}
// If we're at the end, assume completed
- else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value)
+ else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= runtimeTicks)
{
positionTicks = 0;
data.Played = playedToCompletion = true;
@@ -254,7 +256,7 @@ public bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPosi
else
{
// Enforce MinResumeDuration
- var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds;
+ var durationSeconds = TimeSpan.FromTicks(runtimeTicks).TotalSeconds;
if (durationSeconds < _config.Configuration.MinResumeDurationSeconds)
{
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 74a44752d7..d9df23b2aa 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -1267,7 +1267,7 @@ private void UpdateDeviceAccess(User user)
{
if (!string.IsNullOrEmpty(authInfo.DeviceId) && !_deviceManager.CanAccessDevice(user, authInfo.DeviceId))
{
- _sessionManager.Logout(authInfo.AccessToken);
+ _sessionManager.Logout(authInfo);
}
}
}
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index e2e45229e1..20abaf27c2 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -28,8 +28,7 @@ public NetworkManager(ILogger logger, IEnvironmentInfo environment)
Logger = logger;
// In FreeBSD these events cause a crash
- if (environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.BSD &&
- environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Linux)
+ if (environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.BSD)
{
try
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs
index 9f887ba030..db8a093807 100644
--- a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs
@@ -71,14 +71,13 @@ public async Task Execute(CancellationToken cancellationToken, IProgress
var numComplete = 0;
- // Create tasks for each one
- var tasks = packagesToInstall.Select(i => Task.Run(async () =>
+ foreach (var package in packagesToInstall)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
- await _installationManager.InstallPackage(i, true, new SimpleProgress(), cancellationToken).ConfigureAwait(false);
+ await _installationManager.InstallPackage(package, true, new SimpleProgress(), cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -90,11 +89,11 @@ public async Task Execute(CancellationToken cancellationToken, IProgress
}
catch (HttpException ex)
{
- _logger.ErrorException("Error downloading {0}", ex, i.name);
+ _logger.ErrorException("Error downloading {0}", ex, package.name);
}
catch (IOException ex)
{
- _logger.ErrorException("Error updating {0}", ex, i.name);
+ _logger.ErrorException("Error updating {0}", ex, package.name);
}
// Update progress
@@ -106,11 +105,7 @@ public async Task Execute(CancellationToken cancellationToken, IProgress
progress.Report(90 * percent + 10);
}
- }));
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
+ }
progress.Report(100);
}
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 1a2c2ebcc0..d9bc6df3bf 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -34,7 +34,7 @@ public void Initialize()
string[] queries = {
- "create table if not exists AccessTokens (Id GUID PRIMARY KEY NOT NULL, AccessToken TEXT NOT NULL, DeviceId TEXT NOT NULL, AppName TEXT NOT NULL, AppVersion TEXT NOT NULL, DeviceName TEXT NOT NULL, UserId TEXT, IsActive BIT NOT NULL, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
+ "create table if not exists AccessTokens (Id GUID PRIMARY KEY NOT NULL, AccessToken TEXT NOT NULL, DeviceId TEXT NOT NULL, AppName TEXT NOT NULL, AppVersion TEXT NOT NULL, DeviceName TEXT NOT NULL, UserId TEXT, UserName TEXT, IsActive BIT NOT NULL, DateCreated DATETIME NOT NULL, DateLastActivity DATETIME NOT NULL, DateRevoked DATETIME)",
"create index if not exists idx_AccessTokens on AccessTokens(Id)"
};
@@ -44,6 +44,8 @@ public void Initialize()
{
var existingColumnNames = GetColumnNames(db, "AccessTokens");
+ AddColumn(db, "AccessTokens", "UserName", "TEXT", existingColumnNames);
+ AddColumn(db, "AccessTokens", "DateLastActivity", "DATETIME", existingColumnNames);
AddColumn(db, "AccessTokens", "AppVersion", "TEXT", existingColumnNames);
}, TransactionMode);
@@ -72,7 +74,7 @@ public void Update(AuthenticationInfo info, CancellationToken cancellationToken)
{
connection.RunInTransaction(db =>
{
- using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"))
+ using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity, @DateRevoked)"))
{
statement.TryBind("@Id", info.Id.ToGuidBlob());
statement.TryBind("@AccessToken", info.AccessToken);
@@ -82,8 +84,10 @@ public void Update(AuthenticationInfo info, CancellationToken cancellationToken)
statement.TryBind("@AppVersion", info.AppVersion);
statement.TryBind("@DeviceName", info.DeviceName);
statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N")));
+ statement.TryBind("@UserName", info.UserName);
statement.TryBind("@IsActive", info.IsActive);
statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue());
+ statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue());
if (info.DateRevoked.HasValue)
{
@@ -102,7 +106,7 @@ public void Update(AuthenticationInfo info, CancellationToken cancellationToken)
}
}
- private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
+ private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity, DateRevoked from AccessTokens";
private void BindAuthenticationQueryParams(AuthenticationInfoQuery query, IStatement statement)
{
@@ -138,8 +142,6 @@ public QueryResult Get(AuthenticationInfoQuery query)
var whereClauses = new List();
- var startIndex = query.StartIndex ?? 0;
-
if (!string.IsNullOrEmpty(query.AccessToken))
{
whereClauses.Add("AccessToken=@AccessToken");
@@ -176,28 +178,23 @@ public QueryResult Get(AuthenticationInfoQuery query)
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
- if (startIndex > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+ commandText += whereTextWithoutPaging;
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
- pagingWhereText,
- startIndex.ToString(_usCulture)));
- }
+ commandText += " ORDER BY DateLastActivity desc, DateCreated desc";
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
-
- commandText += whereText;
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
+ {
+ var offset = query.StartIndex ?? 0;
- commandText += " ORDER BY DateCreated";
+ if (query.Limit.HasValue || offset > 0)
+ {
+ commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.Limit.HasValue)
- {
- commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ if (offset > 0)
+ {
+ commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
+ }
}
var list = new List();
@@ -304,12 +301,26 @@ private AuthenticationInfo Get(IReadOnlyList reader)
info.UserId = new Guid(reader[6].ToString());
}
- info.IsActive = reader[7].ToBool();
- info.DateCreated = reader[8].ReadDateTime();
+ if (reader[7].SQLiteType != SQLiteType.Null)
+ {
+ info.UserName = reader[7].ToString();
+ }
+
+ info.IsActive = reader[8].ToBool();
+ info.DateCreated = reader[9].ReadDateTime();
+
+ if (reader[10].SQLiteType != SQLiteType.Null)
+ {
+ info.DateLastActivity = reader[10].ReadDateTime();
+ }
+ else
+ {
+ info.DateLastActivity = info.DateCreated;
+ }
- if (reader[9].SQLiteType != SQLiteType.Null)
+ if (reader[11].SQLiteType != SQLiteType.Null)
{
- info.DateRevoked = reader[9].TryReadDateTime();
+ info.DateRevoked = reader[11].TryReadDateTime();
}
return info;
diff --git a/Emby.Server.Implementations/Session/FirebaseSessionController.cs b/Emby.Server.Implementations/Session/FirebaseSessionController.cs
index 98a9c9d9ba..cfe513305e 100644
--- a/Emby.Server.Implementations/Session/FirebaseSessionController.cs
+++ b/Emby.Server.Implementations/Session/FirebaseSessionController.cs
@@ -50,7 +50,7 @@ public bool IsSessionActive
{
get
{
- return (DateTime.UtcNow - Session.LastActivityDate).TotalHours <= 48;
+ return (DateTime.UtcNow - Session.LastActivityDate).TotalDays <= 3;
}
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 25dc3cc4bc..38dd0e319e 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -108,8 +108,6 @@ public SessionManager(IUserDataManager userDataManager, ILogger logger, ILibrary
_deviceManager = deviceManager;
_mediaSourceManager = mediaSourceManager;
_timerFactory = timerFactory;
-
- _deviceManager.DeviceOptionsUpdated += _deviceManager_DeviceOptionsUpdated;
}
private bool _disposed;
@@ -126,17 +124,6 @@ public void CheckDisposed()
}
}
- void _deviceManager_DeviceOptionsUpdated(object sender, GenericEventArgs e)
- {
- foreach (var session in Sessions)
- {
- if (string.Equals(session.DeviceId, e.Argument.Id))
- {
- session.DeviceName = e.Argument.Name;
- }
- }
- }
-
///
/// Gets all connections.
///
@@ -185,19 +172,7 @@ public void UpdateDeviceName(string sessionId, string deviceName)
if (session != null)
{
- var deviceId = session.DeviceId;
-
- if (!string.IsNullOrEmpty(deviceId))
- {
- var device = _deviceManager.GetDevice(deviceId);
-
- if (device != null)
- {
- device = _deviceManager.RegisterDevice(device.Id, deviceName, device.AppName, device.AppVersion, device.LastUserId, device.LastUserName);
-
- session.DeviceName = device.Name;
- }
- }
+ session.DeviceName = deviceName;
}
}
@@ -436,8 +411,6 @@ private SessionInfo GetSessionInfo(string appName, string appVersion, string dev
private SessionInfo CreateSession(string key, string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
{
- DeviceInfo device = null;
-
var sessionInfo = new SessionInfo(this, _logger)
{
Client = appName,
@@ -458,20 +431,6 @@ private SessionInfo CreateSession(string key, string appName, string appVersion,
deviceName = "Network Device";
}
- if (!string.IsNullOrEmpty(deviceId))
- {
- var userIdString = user != null ? user.Id.ToString("N") : null;
- device = _deviceManager.RegisterDevice(deviceId, deviceName, appName, appVersion, userIdString, username);
- }
-
- if (device != null)
- {
- if (!string.IsNullOrEmpty(device.CustomName))
- {
- deviceName = device.CustomName;
- }
- }
-
sessionInfo.DeviceName = deviceName;
OnSessionStarted(sessionInfo);
@@ -1380,7 +1339,7 @@ private async Task AuthenticateNewSessionInternal(Authenti
user = result;
}
- var token = GetAuthorizationToken(user.Id, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
+ var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
EventHelper.FireEventIfNotNull(AuthenticationSucceeded, this, new GenericEventArgs(request), _logger);
@@ -1400,36 +1359,62 @@ private async Task AuthenticateNewSessionInternal(Authenti
};
}
- private string GetAuthorizationToken(Guid userId, string deviceId, string app, string appVersion, string deviceName)
+ private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
DeviceId = deviceId,
IsActive = true,
- UserId = userId,
+ UserId = user.Id,
Limit = 1
- });
- if (existing.Items.Length > 0)
+ }).Items.FirstOrDefault();
+
+ if (existing != null)
{
- var token = existing.Items[0].AccessToken;
- _logger.Info("Reissuing access token: " + token);
- return token;
+ var allExistingForDevice = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ DeviceId = deviceId,
+ IsActive = true
+
+ }).Items;
+
+ foreach (var auth in allExistingForDevice)
+ {
+ if (!string.Equals(auth.AccessToken, existing.AccessToken, StringComparison.Ordinal))
+ {
+ try
+ {
+ Logout(auth);
+ }
+ catch
+ {
+
+ }
+ }
+ }
+
+ _logger.Info("Reissuing access token: " + existing.AccessToken);
+ return existing.AccessToken;
}
+ var now = DateTime.UtcNow;
+
var newToken = new AuthenticationInfo
{
AppName = app,
AppVersion = appVersion,
- DateCreated = DateTime.UtcNow,
+ DateCreated = now,
+ DateLastActivity = now,
DeviceId = deviceId,
DeviceName = deviceName,
- UserId = userId,
+ UserId = user.Id,
IsActive = true,
- AccessToken = Guid.NewGuid().ToString("N")
+ AccessToken = Guid.NewGuid().ToString("N"),
+ UserName = user.Name
};
- _logger.Info("Creating new access token for user {0}", userId);
+ _logger.Info("Creating new access token for user {0}", user.Id);
_authRepo.Create(newToken, CancellationToken.None);
return newToken.AccessToken;
@@ -1444,8 +1429,6 @@ public void Logout(string accessToken)
throw new ArgumentNullException("accessToken");
}
- _logger.Info("Logging out access token {0}", accessToken);
-
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
Limit = 1,
@@ -1455,24 +1438,34 @@ public void Logout(string accessToken)
if (existing != null)
{
- existing.IsActive = false;
+ Logout(existing);
+ }
+ }
+
+ public void Logout(AuthenticationInfo existing)
+ {
+ CheckDisposed();
- _authRepo.Update(existing, CancellationToken.None);
+ _logger.Info("Logging out access token {0}", existing.AccessToken);
- var sessions = Sessions
- .Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
- .ToList();
+ existing.IsActive = false;
+ existing.DateRevoked = DateTime.UtcNow;
- foreach (var session in sessions)
+ _authRepo.Update(existing, CancellationToken.None);
+
+ var sessions = Sessions
+ .Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ foreach (var session in sessions)
+ {
+ try
{
- try
- {
- ReportSessionEnded(session.Id);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error reporting session ended", ex);
- }
+ ReportSessionEnded(session.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error reporting session ended", ex);
}
}
}
@@ -1491,7 +1484,7 @@ public void RevokeUserTokens(Guid userId, string currentAccessToken)
{
if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
{
- Logout(info.AccessToken);
+ Logout(info);
}
}
}
@@ -1612,7 +1605,7 @@ private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource)
fields.Remove(ItemFields.Settings);
fields.Remove(ItemFields.SortName);
fields.Remove(ItemFields.Tags);
- fields.Remove(ItemFields.ThemeSongIds);
+ fields.Remove(ItemFields.ExtraIds);
dtoOptions.Fields = fields.ToArray(fields.Count);
@@ -1702,22 +1695,7 @@ public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, stri
var deviceName = info.DeviceName;
var appName = info.AppName;
- if (!string.IsNullOrEmpty(deviceId))
- {
- // Replace the info from the token with more recent info
- var device = _deviceManager.GetDevice(deviceId);
- if (device != null)
- {
- deviceName = device.Name;
- appName = device.AppName;
-
- if (!string.IsNullOrEmpty(device.AppVersion))
- {
- appVersion = device.AppVersion;
- }
- }
- }
- else
+ if (string.IsNullOrEmpty(deviceId))
{
deviceId = info.DeviceId;
}
@@ -1808,8 +1786,7 @@ public Task SendMessageToUserSessions(List userIds, string name, T data
return Task.WhenAll(tasks);
}
- public Task SendMessageToUserDeviceSessions(string deviceId, string name, T data,
- CancellationToken cancellationToken)
+ public Task SendMessageToUserDeviceSessions(string deviceId, string name, T data, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1830,5 +1807,36 @@ public Task SendMessageToUserDeviceSessions(string deviceId, string name, T d
return Task.WhenAll(tasks);
}
+
+ public Task SendMessageToUserDeviceAndAdminSessions(string deviceId, string name, T data, CancellationToken cancellationToken)
+ {
+ CheckDisposed();
+
+ var sessions = Sessions
+ .Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase) || IsAdminSession(i))
+ .ToList();
+
+ var tasks = sessions.Select(session => Task.Run(async () =>
+ {
+ try
+ {
+ await SendMessageToSession(session, name, data, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error sending message", ex);
+ }
+
+ }, cancellationToken)).ToArray();
+
+ return Task.WhenAll(tasks);
+ }
+
+ private bool IsAdminSession(SessionInfo s)
+ {
+ var user = _userManager.GetUserById(s.UserId);
+
+ return user != null && user.Policy.IsAdministrator;
+ }
}
}
\ No newline at end of file
diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config
index ffc2204a93..540c1d51e6 100644
--- a/Emby.Server.Implementations/packages.config
+++ b/Emby.Server.Implementations/packages.config
@@ -1,15 +1,15 @@
-
-
-
+
+
+
-
-
+
+
@@ -40,7 +40,7 @@
-
+
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index e98915e908..2d0fc9c632 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -88,7 +88,7 @@ protected void AssertCanUpdateUser(IAuthorizationContext authContext, IUserManag
{
var auth = authContext.GetAuthorizationInfo(Request);
- var authenticatedUser = userManager.GetUserById(auth.UserId);
+ var authenticatedUser = auth.User;
// If they're going to update the record of another user, they must be an administrator
if (!userId.Equals(auth.UserId))
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
index 05d0e9615c..92e8dc2e07 100644
--- a/MediaBrowser.Api/Devices/DeviceService.cs
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -7,6 +7,8 @@
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
+using MediaBrowser.Controller.Security;
+using MediaBrowser.Controller.Session;
namespace MediaBrowser.Api.Devices
{
@@ -50,56 +52,17 @@ public class PostCameraUpload : IRequiresRequestStream, IReturnVoid
public Stream RequestStream { get; set; }
}
- [Route("/Devices/Info", "GET", Summary = "Gets device info")]
- [Authenticated]
- public class GetDeviceInfo : IReturn
- {
- [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
- [Route("/Devices/Capabilities", "GET", Summary = "Gets device capabilities")]
- [Authenticated]
- public class GetDeviceCapabilities : IReturn
- {
- [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
- [Route("/Devices/Options", "POST", Summary = "Updates device options")]
- [Authenticated(Roles = "Admin")]
- public class PostDeviceOptions : DeviceOptions, IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
public class DeviceService : BaseApiService
{
private readonly IDeviceManager _deviceManager;
+ private readonly IAuthenticationRepository _authRepo;
+ private readonly ISessionManager _sessionManager;
- public DeviceService(IDeviceManager deviceManager)
+ public DeviceService(IDeviceManager deviceManager, IAuthenticationRepository authRepo, ISessionManager sessionManager)
{
_deviceManager = deviceManager;
- }
-
- public void Post(PostDeviceOptions request)
- {
- _deviceManager.UpdateDeviceInfo(request.Id, new DeviceOptions
- {
- CustomName = request.CustomName,
- CameraUploadPath = request.CameraUploadPath
- });
- }
-
- public object Get(GetDeviceInfo request)
- {
- return ToOptimizedResult(_deviceManager.GetDevice(request.Id));
- }
-
- public object Get(GetDeviceCapabilities request)
- {
- return ToOptimizedResult(_deviceManager.GetCapabilities(request.Id));
+ _authRepo = authRepo;
+ _sessionManager = sessionManager;
}
public object Get(GetDevices request)
@@ -114,7 +77,17 @@ public object Get(GetCameraUploads request)
public void Delete(DeleteDevice request)
{
- _deviceManager.DeleteDevice(request.Id);
+ var sessions = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ DeviceId = request.Id,
+ IsActive = true
+
+ }).Items;
+
+ foreach (var session in sessions)
+ {
+ _sessionManager.Logout(session);
+ }
}
public Task Post(PostCameraUpload request)
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 6bd993848c..46d136b481 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -802,7 +802,7 @@ public Task Get(GetDownload request)
var item = _libraryManager.GetItemById(request.Id);
var auth = _authContext.GetAuthorizationInfo(Request);
- var user = _userManager.GetUserById(auth.UserId);
+ var user = auth.User;
if (user != null)
{
@@ -1023,7 +1023,7 @@ public void Delete(DeleteItems request)
{
var item = _libraryManager.GetItemById(i);
var auth = _authContext.GetAuthorizationInfo(Request);
- var user = _userManager.GetUserById(auth.UserId);
+ var user = auth.User;
if (!item.CanDelete(user))
{
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 199ac7ce94..b9e0282e68 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -105,13 +105,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index 4150a42f21..74ad88e7b2 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -27,6 +27,8 @@ public class GetSessions : IReturn
[ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; }
+
+ public int? ActiveWithinSeconds { get; set; }
}
///
@@ -199,9 +201,6 @@ public class PostCapabilities : IReturnVoid
[ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string SupportedCommands { get; set; }
- [ApiMember(Name = "MessageCallbackUrl", Description = "A url to post messages to, including remote control commands.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string MessageCallbackUrl { get; set; }
-
[ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
public bool SupportsMediaControl { get; set; }
@@ -211,8 +210,6 @@ public class PostCapabilities : IReturnVoid
[ApiMember(Name = "SupportsPersistentIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
public bool SupportsPersistentIdentifier { get; set; }
- public bool SupportsContentUploading { get; set; }
-
public PostCapabilities()
{
SupportsPersistentIdentifier = true;
@@ -367,6 +364,12 @@ public object Get(GetSessions request)
result = result.Where(i => !i.UserId.Equals(Guid.Empty));
}
+ if (request.ActiveWithinSeconds.HasValue && request.ActiveWithinSeconds.Value > 0)
+ {
+ var minActiveDate = DateTime.UtcNow.AddSeconds(0 - request.ActiveWithinSeconds.Value);
+ result = result.Where(i => i.LastActivityDate >= minActiveDate);
+ }
+
result = result.Where(i =>
{
var deviceId = i.DeviceId;
@@ -503,12 +506,8 @@ public void Post(PostCapabilities request)
SupportsMediaControl = request.SupportsMediaControl,
- MessageCallbackUrl = request.MessageCallbackUrl,
-
SupportsSync = request.SupportsSync,
- SupportsContentUploading = request.SupportsContentUploading,
-
SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
});
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index 92538b91f8..c98d253a2e 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -276,6 +276,8 @@ protected BaseItemsRequest()
[ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ArtistIds { get; set; }
+ public string AlbumArtistIds { get; set; }
+
[ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Albums { get; set; }
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index dd28841955..6a66b06a4b 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -287,10 +287,13 @@ private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions
HasThemeSong = request.HasThemeSong,
HasThemeVideo = request.HasThemeVideo,
HasTrailer = request.HasTrailer,
+ IsHD = request.IsHD,
+ Is4K = request.Is4K,
Tags = request.GetTags(),
OfficialRatings = request.GetOfficialRatings(),
Genres = request.GetGenres(),
ArtistIds = GetGuids(request.ArtistIds),
+ AlbumArtistIds = GetGuids(request.AlbumArtistIds),
GenreIds = GetGuids(request.GenreIds),
StudioIds = GetGuids(request.StudioIds),
Person = request.Person,
@@ -307,38 +310,11 @@ private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions
MinCriticRating = request.MinCriticRating,
ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId),
ParentIndexNumber = request.ParentIndexNumber,
- AiredDuringSeason = request.AiredDuringSeason,
EnableTotalRecordCount = request.EnableTotalRecordCount,
ExcludeItemIds = GetGuids(request.ExcludeItemIds),
DtoOptions = dtoOptions
};
- if (request.IsHD.HasValue)
- {
- var threshold = 1200;
- if (request.IsHD.Value)
- {
- query.MinWidth = threshold;
- }
- else
- {
- query.MaxWidth = threshold - 1;
- }
- }
-
- if (request.Is4K.HasValue)
- {
- var threshold = 3800;
- if (request.Is4K.Value)
- {
- query.MinWidth = threshold;
- }
- else
- {
- query.MaxWidth = threshold - 1;
- }
- }
-
if (!string.IsNullOrWhiteSpace(request.Ids))
{
query.CollapseBoxSetItems = false;
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index dbcd61ec6a..bb92fad7d5 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -347,40 +347,12 @@ private BaseItemDto[] GetAsync(GetSpecialFeatures request)
_libraryManager.GetUserRootFolder() :
_libraryManager.GetItemById(request.Id);
- var series = item as Series;
-
- // Get them from the child tree
- if (series != null)
- {
- var dtoOptions = GetDtoOptions(_authContext, request);
-
- // Avoid implicitly captured closure
- var currentUser = user;
-
- var dtos = series
- .GetEpisodes(user, dtoOptions)
- .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
- .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, currentUser));
-
- return dtos.ToArray();
- }
-
- var movie = item as IHasSpecialFeatures;
-
- // Get them from the db
- if (movie != null)
- {
- var dtoOptions = GetDtoOptions(_authContext, request);
-
- var dtos = movie.SpecialFeatureIds
- .Select(_libraryManager.GetItemById)
- .OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
+ var dtoOptions = GetDtoOptions(_authContext, request);
- return dtos.ToArray();
- }
+ var dtos = item.GetDisplayExtras()
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
- return new BaseItemDto[] { };
+ return dtos.ToArray();
}
///
@@ -394,22 +366,9 @@ public object Get(GetLocalTrailers request)
var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
- List trailerIds = null;
-
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
- {
- trailerIds = hasTrailers.GetTrailerIds();
- }
- else
- {
- trailerIds = new List();
- }
-
var dtoOptions = GetDtoOptions(_authContext, request);
- var dtos = trailerIds
- .Select(_libraryManager.GetItemById)
+ var dtos = item.GetExtras(new[] { ExtraType.Trailer })
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
.ToArray();
@@ -507,7 +466,7 @@ public async Task Get(GetIntros request)
/// The request.
public object Post(MarkFavoriteItem request)
{
- var dto = MarkFavorite(request.UserId, request.Id, true);
+ var dto = MarkFavorite(request.UserId, request.Id, true);
return ToOptimizedResult(dto);
}
@@ -541,7 +500,7 @@ private UserItemDataDto MarkFavorite(Guid userId, Guid itemId, bool isFavorite)
// Set favorite status
data.IsFavorite = isFavorite;
- _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
return _userDataRepository.GetUserDataDto(item, user);
}
@@ -563,7 +522,7 @@ public object Delete(DeleteUserItemRating request)
/// The request.
public object Post(UpdateUserItemRating request)
{
- var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes);
+ var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes);
return ToOptimizedResult(dto);
}
@@ -585,7 +544,7 @@ private UserItemDataDto UpdateUserItemRating(Guid userId, Guid itemId, bool? lik
data.Likes = likes;
- _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
return _userDataRepository.GetUserDataDto(item, user);
}
diff --git a/MediaBrowser.Api/packages.config b/MediaBrowser.Api/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/MediaBrowser.Api/packages.config
+++ b/MediaBrowser.Api/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
index 3d4eaba3b9..68f8ce71d8 100644
--- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
+++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
@@ -57,13 +57,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index 62c3c906cd..05874ec2cf 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -450,13 +450,9 @@ protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult
{
var val = reader.ReadElementContentAsString();
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
+ if (!string.IsNullOrWhiteSpace(val))
{
- if (!string.IsNullOrWhiteSpace(val))
- {
- hasTrailers.AddTrailerUrl(val);
- }
+ item.AddTrailerUrl(val);
}
break;
}
@@ -482,11 +478,7 @@ protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult
{
using (var subtree = reader.ReadSubtree())
{
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
- {
- FetchDataFromTrailersNode(subtree, hasTrailers);
- }
+ FetchDataFromTrailersNode(subtree, item);
}
}
else
@@ -1007,7 +999,7 @@ private void FetchDataFromPersonsNode(XmlReader reader, MetadataResult item)
}
}
- private void FetchDataFromTrailersNode(XmlReader reader, IHasTrailers item)
+ private void FetchDataFromTrailersNode(XmlReader reader, T item)
{
reader.MoveToContent();
reader.Read();
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index 5e2e56450a..81622f54c5 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -251,20 +251,16 @@ public static void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManag
}
}
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
+ if (item.RemoteTrailers.Length > 0)
{
- if (hasTrailers.RemoteTrailers.Length > 0)
- {
- writer.WriteStartElement("Trailers");
-
- foreach (var trailer in hasTrailers.RemoteTrailers)
- {
- writer.WriteElementString("Trailer", trailer.Url);
- }
+ writer.WriteStartElement("Trailers");
- writer.WriteEndElement();
+ foreach (var trailer in item.RemoteTrailers)
+ {
+ writer.WriteElementString("Trailer", trailer.Url);
}
+
+ writer.WriteEndElement();
}
if (item.ProductionLocations.Length > 0)
diff --git a/MediaBrowser.LocalMetadata/packages.config b/MediaBrowser.LocalMetadata/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/MediaBrowser.LocalMetadata/packages.config
+++ b/MediaBrowser.LocalMetadata/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 1e13b6565c..4c9312b83b 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -309,17 +309,17 @@ public IEnumerable> GetMetadataProviders(BaseItem item,
{
var globalMetadataOptions = GetMetadataOptions(item);
- return GetMetadataProvidersInternal(item, libraryOptions, globalMetadataOptions, false, false, true);
+ return GetMetadataProvidersInternal(item, libraryOptions, globalMetadataOptions, false, false);
}
- private IEnumerable> GetMetadataProvidersInternal(BaseItem item, LibraryOptions libraryOptions, MetadataOptions globalMetadataOptions, bool includeDisabled, bool forceEnableInternetMetadata, bool checkIsOwnedItem)
+ private IEnumerable> GetMetadataProvidersInternal(BaseItem item, LibraryOptions libraryOptions, MetadataOptions globalMetadataOptions, bool includeDisabled, bool forceEnableInternetMetadata)
where T : BaseItem
{
// Avoid implicitly captured closure
var currentOptions = globalMetadataOptions;
return _metadataProviders.OfType>()
- .Where(i => CanRefresh(i, item, libraryOptions, currentOptions, includeDisabled, forceEnableInternetMetadata, checkIsOwnedItem))
+ .Where(i => CanRefresh(i, item, libraryOptions, currentOptions, includeDisabled, forceEnableInternetMetadata))
.OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, globalMetadataOptions))
.ThenBy(GetDefaultOrder);
}
@@ -332,7 +332,7 @@ private IEnumerable GetRemoteImageProviders(BaseItem item,
return GetImageProviders(item, libraryOptions, options, new ImageRefreshOptions(new DirectoryService(_logger, _fileSystem)), includeDisabled).OfType();
}
- private bool CanRefresh(IMetadataProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, bool includeDisabled, bool forceEnableInternetMetadata, bool checkIsOwnedItem)
+ private bool CanRefresh(IMetadataProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, bool includeDisabled, bool forceEnableInternetMetadata)
{
if (!includeDisabled)
{
@@ -357,9 +357,9 @@ private bool CanRefresh(IMetadataProvider provider, BaseItem item, LibraryOption
}
// If this restriction is ever lifted, movie xml providers will have to be updated to prevent owned items like trailers from reading those files
- if (checkIsOwnedItem && item.ExtraType.HasValue)
+ if (!item.OwnerId.Equals(Guid.Empty))
{
- if (provider is ILocalMetadataProvider)
+ if (provider is ILocalMetadataProvider || provider is IRemoteMetadataProvider)
{
return false;
}
@@ -539,7 +539,7 @@ private MetadataPluginSummary GetPluginSummary()
private void AddMetadataPlugins(List list, T item, LibraryOptions libraryOptions, MetadataOptions options)
where T : BaseItem
{
- var providers = GetMetadataProvidersInternal(item, libraryOptions, options, true, true, false).ToList();
+ var providers = GetMetadataProvidersInternal(item, libraryOptions, options, true, true).ToList();
// Locals
list.AddRange(providers.Where(i => (i is ILocalMetadataProvider)).Select(i => new MetadataPlugin
@@ -769,7 +769,7 @@ public async Task> GetRemoteSearchResults(referenceItem, libraryOptions, options, searchInfo.IncludeDisabledProviders, false, false)
+ var providers = GetMetadataProvidersInternal(referenceItem, libraryOptions, options, searchInfo.IncludeDisabledProviders, false)
.OfType>();
if (!string.IsNullOrEmpty(searchInfo.SearchProviderName))
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index 30ecf5e9b8..3a961fe0ec 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -274,15 +274,9 @@ private static void MergeCriticRating(BaseItem source, BaseItem target, Metadata
private static void MergeTrailers(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
- var sourceCast = source as IHasTrailers;
- var targetCast = target as IHasTrailers;
-
- if (sourceCast != null && targetCast != null)
+ if (replaceData || target.RemoteTrailers.Length == 0)
{
- if (replaceData || targetCast.RemoteTrailers.Length == 0)
- {
- targetCast.RemoteTrailers = sourceCast.RemoteTrailers;
- }
+ target.RemoteTrailers = source.RemoteTrailers;
}
}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 9b837ce995..2698d3d96d 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -140,13 +140,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
@@ -241,7 +241,7 @@
True
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index efd9cd2dad..8a409f9cfe 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -305,19 +305,14 @@ private void ProcessMainInfo(MetadataResult resultItem, TmdbSettingsResult se
// movie.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList();
//}
- if (movieData.trailers != null && movieData.trailers.youtube != null &&
- movieData.trailers.youtube.Count > 0)
+ if (movieData.trailers != null && movieData.trailers.youtube != null)
{
- var hasTrailers = movie as IHasTrailers;
- if (hasTrailers != null)
+ movie.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
{
- hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
- {
- Url = string.Format("https://www.youtube.com/watch?v={0}", i.source),
- Name = i.name
+ Url = string.Format("https://www.youtube.com/watch?v={0}", i.source),
+ Name = i.name
- }).ToArray();
- }
+ }).ToArray();
}
}
diff --git a/MediaBrowser.Providers/packages.config b/MediaBrowser.Providers/packages.config
index a913db587a..4456c940e3 100644
--- a/MediaBrowser.Providers/packages.config
+++ b/MediaBrowser.Providers/packages.config
@@ -1,7 +1,7 @@
-
-
+
+
@@ -32,7 +32,7 @@
-
+
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index 3bc2ddfe7d..8ea812e8db 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -51,20 +51,19 @@
..\packages\Emby.XmlTv.1.0.14\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
-
- ..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll
- True
+
+ ..\packages\ServiceStack.Text.5.1.0\lib\net45\ServiceStack.Text.dll
-
- ..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll
+
+ ..\packages\SharpCompress.0.21.1\lib\net45\SharpCompress.dll
..\packages\SimpleInjector.4.3.0\lib\net45\SimpleInjector.dll
@@ -87,12 +86,9 @@
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
-
- ..\packages\System.Threading.Tasks.Extensions.4.5.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
-
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index a445a0f799..8a01163440 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -98,7 +98,7 @@ private static void RunApplication(ServerApplicationPaths appPaths, ILogManager
var environmentInfo = GetEnvironmentInfo(options);
- var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, null, appPaths.TempDirectory);
+ var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, null, appPaths.TempDirectory, true);
FileSystem = fileSystem;
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index f374e88bbd..cd97f1d94e 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -1,15 +1,14 @@
-
-
-
-
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 682db6d062..cfd8e9c125 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -330,7 +330,7 @@ private static void RunApplication(ServerApplicationPaths appPaths, ILogManager
{
var environmentInfo = new EnvironmentInfo();
- var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, null, appPaths.TempDirectory);
+ var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, null, appPaths.TempDirectory, false);
FileSystem = fileSystem;
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 54afca95d6..70d97a4e6b 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -77,20 +77,19 @@
..\packages\Emby.XmlTv.1.0.14\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
-
- ..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll
- True
+
+ ..\packages\ServiceStack.Text.5.1.0\lib\net45\ServiceStack.Text.dll
-
- ..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll
+
+ ..\packages\SharpCompress.0.21.1\lib\net45\SharpCompress.dll
..\packages\SimpleInjector.4.3.0\lib\net45\SimpleInjector.dll
@@ -116,13 +115,10 @@
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
-
- ..\packages\System.Threading.Tasks.Extensions.4.5.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
-
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 2b15095326..34cd2e9548 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,15 +1,14 @@
-
-
-
-
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
index 583740b01e..2ae356a178 100644
--- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj
+++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
@@ -41,13 +41,13 @@
..\ThirdParty\emby\Emby.Server.MediaEncoding.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/MediaBrowser.Tests/packages.config b/MediaBrowser.Tests/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/MediaBrowser.Tests/packages.config
+++ b/MediaBrowser.Tests/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index c8a17ddeca..74b7c491b4 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -46,13 +46,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js
index 2df2de801c..fd2ae5306d 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js
@@ -1 +1 @@
-define(["localassetmanager"],function(localassetmanager){"use strict";function processDownloadStatus(apiClient,serverInfo,options){return console.log("[mediasync] Begin processDownloadStatus"),localassetmanager.resyncTransfers().then(function(){return localassetmanager.getServerItems(serverInfo.Id).then(function(items){console.log("[mediasync] Begin processDownloadStatus getServerItems completed");var p=Promise.resolve(),cnt=0;return items.filter(function(item){return"transferring"===item.SyncStatus||"queued"===item.SyncStatus}).forEach(function(item){p=p.then(function(){return reportTransfer(apiClient,item)}),cnt++}),p.then(function(){return console.log("[mediasync] Exit processDownloadStatus. Items reported: "+cnt.toString()),Promise.resolve()})})})}function reportTransfer(apiClient,item){return localassetmanager.getItemFileSize(item.LocalPath).then(function(size){return size>0?apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function(){return item.SyncStatus="synced",localassetmanager.addOrUpdateLocalItem(item)},function(error){return console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred",error),item.SyncStatus="error",localassetmanager.addOrUpdateLocalItem(item)}):localassetmanager.isDownloadFileInQueue(item.LocalPath).then(function(result){return result?Promise.resolve():(console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item."),localassetmanager.removeLocalItem(item).then(function(){return console.log("[mediasync] reportTransfer: Item deleted."),Promise.resolve()},function(err2){return console.log("[mediasync] reportTransfer: Failed to delete item.",err2),Promise.resolve()}))})},function(error){return console.error("[mediasync] reportTransfer: error on getItemFileSize. Deleting item.",error),localassetmanager.removeLocalItem(item).then(function(){return console.log("[mediasync] reportTransfer: Item deleted."),Promise.resolve()},function(err2){return console.log("[mediasync] reportTransfer: Failed to delete item.",err2),Promise.resolve()})})}function reportOfflineActions(apiClient,serverInfo){return console.log("[mediasync] Begin reportOfflineActions"),localassetmanager.getUserActions(serverInfo.Id).then(function(actions){return actions.length?apiClient.reportOfflineActions(actions).then(function(){return localassetmanager.deleteUserActions(actions).then(function(){return console.log("[mediasync] Exit reportOfflineActions (actions reported and deleted.)"),Promise.resolve()})},function(err){return console.error("[mediasync] error on apiClient.reportOfflineActions: "+err.toString()),localassetmanager.deleteUserActions(actions)}):(console.log("[mediasync] Exit reportOfflineActions (no actions)"),Promise.resolve())})}function syncData(apiClient,serverInfo){return console.log("[mediasync] Begin syncData"),localassetmanager.getServerItems(serverInfo.Id).then(function(items){var completedItems=items.filter(function(item){return item&&("synced"===item.SyncStatus||"error"===item.SyncStatus)}),request={TargetId:apiClient.deviceId(),LocalItemIds:completedItems.map(function(xitem){return xitem.ItemId})};return apiClient.syncData(request).then(function(result){return afterSyncData(apiClient,serverInfo,result).then(function(){return console.log("[mediasync] Exit syncData"),Promise.resolve()},function(err){return console.error("[mediasync] Error in syncData: "+err.toString()),Promise.resolve()})})})}function afterSyncData(apiClient,serverInfo,syncDataResult){console.log("[mediasync] Begin afterSyncData");var p=Promise.resolve();return syncDataResult.ItemIdsToRemove&&syncDataResult.ItemIdsToRemove.length>0&&syncDataResult.ItemIdsToRemove.forEach(function(itemId){p=p.then(function(){return removeLocalItem(itemId,serverInfo.Id)})}),p=p.then(function(){return removeObsoleteContainerItems(serverInfo.Id)}),p.then(function(){return console.log("[mediasync] Exit afterSyncData"),Promise.resolve()})}function removeObsoleteContainerItems(serverId){return console.log("[mediasync] Begin removeObsoleteContainerItems"),localassetmanager.removeObsoleteContainerItems(serverId)}function removeLocalItem(itemId,serverId){return console.log("[mediasync] Begin removeLocalItem"),localassetmanager.getLocalItem(serverId,itemId).then(function(item){return item?localassetmanager.removeLocalItem(item):Promise.resolve()})}function getNewMedia(apiClient,downloadCount){return console.log("[mediasync] Begin getNewMedia"),apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems){var p=Promise.resolve(),currentCount=downloadCount;return jobItems.forEach(function(jobItem){currentCount++<=10&&(p=p.then(function(){return getNewItem(jobItem,apiClient)}))}),p.then(function(){return console.log("[mediasync] Exit getNewMedia"),Promise.resolve()})})}function afterMediaDownloaded(apiClient,jobItem,localItem){return console.log("[mediasync] Begin afterMediaDownloaded"),getImages(apiClient,jobItem,localItem).then(function(){var libraryItem=jobItem.Item;return downloadParentItems(apiClient,jobItem,libraryItem).then(function(){return getSubtitles(apiClient,jobItem,localItem)})})}function createLocalItem(libraryItem,jobItem){console.log("[localassetmanager] Begin createLocalItem");var item={Item:libraryItem,ItemId:libraryItem.Id,ServerId:libraryItem.ServerId,Id:libraryItem.Id};return jobItem&&(item.SyncJobItemId=jobItem.SyncJobItemId),console.log("[localassetmanager] End createLocalItem"),item}function getNewItem(jobItem,apiClient){console.log("[mediasync] Begin getNewItem");var libraryItem=jobItem.Item;return localassetmanager.getLocalItem(libraryItem.ServerId,libraryItem.Id).then(function(existingItem){if(existingItem&&("queued"===existingItem.SyncStatus||"transferring"===existingItem.SyncStatus||"synced"===existingItem.SyncStatus)&&(console.log("[mediasync] getNewItem: getLocalItem found existing item"),localassetmanager.enableBackgroundCompletion()))return afterMediaDownloaded(apiClient,jobItem,existingItem);libraryItem.CanDelete=!1,libraryItem.CanDownload=!1,libraryItem.SupportsSync=!1,libraryItem.People=[],libraryItem.Chapters=[],libraryItem.Studios=[],libraryItem.SpecialFeatureCount=null,libraryItem.LocalTrailerCount=null,libraryItem.RemoteTrailers=[];var localItem=createLocalItem(libraryItem,jobItem);return localItem.SyncStatus="queued",downloadMedia(apiClient,jobItem,localItem)})}function downloadParentItems(apiClient,jobItem,libraryItem){var p=Promise.resolve();return libraryItem.SeriesId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.SeriesId)})),libraryItem.SeasonId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.SeasonId).then(function(seasonItem){return libraryItem.SeasonPrimaryImageTag=(seasonItem.Item.ImageTags||{}).Primary,Promise.resolve()})})),libraryItem.AlbumId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.AlbumId)})),p}function downloadItem(apiClient,itemId){return apiClient.getItem(apiClient.getCurrentUserId(),itemId).then(function(downloadedItem){downloadedItem.CanDelete=!1,downloadedItem.CanDownload=!1,downloadedItem.SupportsSync=!1,downloadedItem.People=[],downloadedItem.SpecialFeatureCount=null,downloadedItem.BackdropImageTags=null,downloadedItem.ParentBackdropImageTags=null,downloadedItem.ParentArtImageTag=null,downloadedItem.ParentLogoImageTag=null;var localItem=createLocalItem(downloadedItem,null);return localassetmanager.addOrUpdateLocalItem(localItem).then(function(){return Promise.resolve(localItem)},function(err){return console.error("[mediasync] downloadItem failed: "+err.toString()),Promise.resolve(null)})})}function ensureLocalPathParts(localItem,jobItem){if(!localItem.LocalPathParts){var libraryItem=localItem.Item,parts=localassetmanager.getDirectoryPath(libraryItem);parts.push(localassetmanager.getLocalFileName(libraryItem,jobItem.OriginalFileName)),localItem.LocalPathParts=parts}}function downloadMedia(apiClient,jobItem,localItem){var url=apiClient.getUrl("Sync/JobItems/"+jobItem.SyncJobItemId+"/File",{api_key:apiClient.accessToken()});return ensureLocalPathParts(localItem,jobItem),localassetmanager.downloadFile(url,localItem).then(function(result){console.log("[mediasync] downloadMedia: localassetmanager.downloadFile returned.");var localPath=result.path,libraryItem=localItem.Item;if(localPath&&libraryItem.MediaSources)for(var i=0;i2?Promise.resolve():reportOfflineActions(apiClient,serverInfo).then(function(){return getNewMedia(apiClient,downloadCount).then(function(){return syncData(apiClient,serverInfo).then(function(){return console.log("[mediasync]************************************* Exit sync"),Promise.resolve()})})})})})},function(err){console.error(err.toString())})}:self.sync=function(apiClient,serverInfo,options){return console.log("[mediasync]************************************* Start sync"),checkLocalFileExistence(apiClient,serverInfo,options).then(function(){return syncData(apiClient,serverInfo).then(function(){return processDownloadStatus(apiClient,serverInfo,options).then(function(){return localassetmanager.getDownloadItemCount().then(function(downloadCount){return!0===options.syncCheckProgressOnly&&downloadCount>2?Promise.resolve():reportOfflineActions(apiClient,serverInfo).then(function(){return getNewMedia(apiClient,downloadCount).then(function(){return syncData(apiClient,serverInfo)})})})})})},function(err){console.error(err.toString())})}}});
\ No newline at end of file
+define(["localassetmanager"],function(localassetmanager){"use strict";function processDownloadStatus(apiClient,serverInfo,options){return console.log("[mediasync] Begin processDownloadStatus"),localassetmanager.resyncTransfers().then(function(){return localassetmanager.getServerItems(serverInfo.Id).then(function(items){console.log("[mediasync] Begin processDownloadStatus getServerItems completed");var p=Promise.resolve(),cnt=0;return items.filter(function(item){return"transferring"===item.SyncStatus||"queued"===item.SyncStatus}).forEach(function(item){p=p.then(function(){return reportTransfer(apiClient,item)}),cnt++}),p.then(function(){return console.log("[mediasync] Exit processDownloadStatus. Items reported: "+cnt.toString()),Promise.resolve()})})})}function reportTransfer(apiClient,item){return localassetmanager.getItemFileSize(item.LocalPath).then(function(size){return size>0?apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function(){return item.SyncStatus="synced",localassetmanager.addOrUpdateLocalItem(item)},function(error){return console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred",error),item.SyncStatus="error",localassetmanager.addOrUpdateLocalItem(item)}):localassetmanager.isDownloadFileInQueue(item.LocalPath).then(function(result){return result?Promise.resolve():(console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item."),localassetmanager.removeLocalItem(item).then(function(){return console.log("[mediasync] reportTransfer: Item deleted."),Promise.resolve()},function(err2){return console.log("[mediasync] reportTransfer: Failed to delete item.",err2),Promise.resolve()}))})},function(error){return console.error("[mediasync] reportTransfer: error on getItemFileSize. Deleting item.",error),localassetmanager.removeLocalItem(item).then(function(){return console.log("[mediasync] reportTransfer: Item deleted."),Promise.resolve()},function(err2){return console.log("[mediasync] reportTransfer: Failed to delete item.",err2),Promise.resolve()})})}function reportOfflineActions(apiClient,serverInfo){return console.log("[mediasync] Begin reportOfflineActions"),localassetmanager.getUserActions(serverInfo.Id).then(function(actions){return actions.length?apiClient.reportOfflineActions(actions).then(function(){return localassetmanager.deleteUserActions(actions).then(function(){return console.log("[mediasync] Exit reportOfflineActions (actions reported and deleted.)"),Promise.resolve()})},function(err){return console.error("[mediasync] error on apiClient.reportOfflineActions: "+err.toString()),localassetmanager.deleteUserActions(actions)}):(console.log("[mediasync] Exit reportOfflineActions (no actions)"),Promise.resolve())})}function syncData(apiClient,serverInfo){return console.log("[mediasync] Begin syncData"),localassetmanager.getServerItems(serverInfo.Id).then(function(items){var completedItems=items.filter(function(item){return item&&("synced"===item.SyncStatus||"error"===item.SyncStatus)}),request={TargetId:apiClient.deviceId(),LocalItemIds:completedItems.map(function(xitem){return xitem.ItemId})};return apiClient.syncData(request).then(function(result){return afterSyncData(apiClient,serverInfo,result).then(function(){return console.log("[mediasync] Exit syncData"),Promise.resolve()},function(err){return console.error("[mediasync] Error in syncData: "+err.toString()),Promise.resolve()})})})}function afterSyncData(apiClient,serverInfo,syncDataResult){console.log("[mediasync] Begin afterSyncData");var p=Promise.resolve();return syncDataResult.ItemIdsToRemove&&syncDataResult.ItemIdsToRemove.length>0&&syncDataResult.ItemIdsToRemove.forEach(function(itemId){p=p.then(function(){return removeLocalItem(itemId,serverInfo.Id)})}),p=p.then(function(){return removeObsoleteContainerItems(serverInfo.Id)}),p.then(function(){return console.log("[mediasync] Exit afterSyncData"),Promise.resolve()})}function removeObsoleteContainerItems(serverId){return console.log("[mediasync] Begin removeObsoleteContainerItems"),localassetmanager.removeObsoleteContainerItems(serverId)}function removeLocalItem(itemId,serverId){return console.log("[mediasync] Begin removeLocalItem"),localassetmanager.getLocalItem(serverId,itemId).then(function(item){return item?localassetmanager.removeLocalItem(item):Promise.resolve()})}function getNewMedia(apiClient,downloadCount){return console.log("[mediasync] Begin getNewMedia"),apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems){var p=Promise.resolve(),currentCount=downloadCount;return jobItems.forEach(function(jobItem){currentCount++<=10&&(p=p.then(function(){return getNewItem(jobItem,apiClient)}))}),p.then(function(){return console.log("[mediasync] Exit getNewMedia"),Promise.resolve()})})}function afterMediaDownloaded(apiClient,jobItem,localItem){return console.log("[mediasync] Begin afterMediaDownloaded"),getImages(apiClient,jobItem,localItem).then(function(){var libraryItem=jobItem.Item;return downloadParentItems(apiClient,jobItem,libraryItem).then(function(){return getSubtitles(apiClient,jobItem,localItem)})})}function createLocalItem(libraryItem,jobItem){console.log("[localassetmanager] Begin createLocalItem");var item={Item:libraryItem,ItemId:libraryItem.Id,ServerId:libraryItem.ServerId,Id:libraryItem.Id};return jobItem&&(item.SyncJobItemId=jobItem.SyncJobItemId),console.log("[localassetmanager] End createLocalItem"),item}function getNewItem(jobItem,apiClient){console.log("[mediasync] Begin getNewItem");var libraryItem=jobItem.Item;return localassetmanager.getLocalItem(libraryItem.ServerId,libraryItem.Id).then(function(existingItem){if(existingItem&&("queued"===existingItem.SyncStatus||"transferring"===existingItem.SyncStatus||"synced"===existingItem.SyncStatus)&&(console.log("[mediasync] getNewItem: getLocalItem found existing item"),localassetmanager.enableBackgroundCompletion()))return afterMediaDownloaded(apiClient,jobItem,existingItem);libraryItem.CanDelete=!1,libraryItem.CanDownload=!1,libraryItem.SupportsSync=!1,libraryItem.People=[],libraryItem.Chapters=[],libraryItem.Studios=[],libraryItem.SpecialFeatureCount=null,libraryItem.LocalTrailerCount=null,libraryItem.RemoteTrailers=[];var localItem=createLocalItem(libraryItem,jobItem);return localItem.SyncStatus="queued",downloadMedia(apiClient,jobItem,localItem)})}function downloadParentItems(apiClient,jobItem,libraryItem){var p=Promise.resolve();return libraryItem.SeriesId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.SeriesId)})),libraryItem.SeasonId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.SeasonId).then(function(seasonItem){return libraryItem.SeasonPrimaryImageTag=(seasonItem.Item.ImageTags||{}).Primary,Promise.resolve()})})),libraryItem.AlbumId&&(p=p.then(function(){return downloadItem(apiClient,libraryItem.AlbumId)})),p}function downloadItem(apiClient,itemId){return apiClient.getItem(apiClient.getCurrentUserId(),itemId).then(function(downloadedItem){downloadedItem.CanDelete=!1,downloadedItem.CanDownload=!1,downloadedItem.SupportsSync=!1,downloadedItem.People=[],downloadedItem.SpecialFeatureCount=null,downloadedItem.BackdropImageTags=null,downloadedItem.ParentBackdropImageTags=null,downloadedItem.ParentArtImageTag=null,downloadedItem.ParentLogoImageTag=null;var localItem=createLocalItem(downloadedItem,null);return localassetmanager.addOrUpdateLocalItem(localItem).then(function(){return Promise.resolve(localItem)},function(err){return console.error("[mediasync] downloadItem failed: "+err.toString()),Promise.resolve(null)})})}function ensureLocalPathParts(localItem,jobItem){if(!localItem.LocalPathParts){var libraryItem=localItem.Item,parts=localassetmanager.getDirectoryPath(libraryItem);parts.push(localassetmanager.getLocalFileName(libraryItem,jobItem.OriginalFileName)),localItem.LocalPathParts=parts}}function downloadMedia(apiClient,jobItem,localItem){var url=apiClient.getUrl("Sync/JobItems/"+jobItem.SyncJobItemId+"/File",{api_key:apiClient.accessToken()});return ensureLocalPathParts(localItem,jobItem),localassetmanager.downloadFile(url,localItem).then(function(result){console.log("[mediasync] downloadMedia: localassetmanager.downloadFile returned.");var localPath=result.path,libraryItem=localItem.Item;if(localPath&&libraryItem.MediaSources)for(var i=0;i2?Promise.resolve():reportOfflineActions(apiClient,serverInfo).then(function(){return getNewMedia(apiClient,downloadCount).then(function(){return syncData(apiClient,serverInfo).then(function(){return console.log("[mediasync]************************************* Exit sync"),Promise.resolve()})})})})})},function(err){console.error(err.toString())})}:self.sync=function(apiClient,serverInfo,options){return console.log("[mediasync]************************************* Start sync"),checkLocalFileExistence(apiClient,serverInfo,options).then(function(){return syncData(apiClient,serverInfo).then(function(){return processDownloadStatus(apiClient,serverInfo,options).then(function(){return localassetmanager.getDownloadItemCount().then(function(downloadCount){return!0===options.syncCheckProgressOnly&&downloadCount>2?Promise.resolve():reportOfflineActions(apiClient,serverInfo).then(function(){return getNewMedia(apiClient,downloadCount).then(function(){return syncData(apiClient,serverInfo)})})})})})},function(err){console.error(err.toString())})}}});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css
index d51478a3e3..346716d26d 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css
+++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css
@@ -1 +1 @@
-.card,.card:focus{font-weight:inherit!important}.card,.cardBox,.cardContent,.textActionButton{-webkit-tap-highlight-color:transparent;outline:0!important}button::-moz-focus-inner{padding:0;border:0}button{-webkit-border-fit:border!important}.card{border:0;font-size:inherit!important;font-family:inherit!important;text-transform:none;background:0 0!important;margin:0;padding:0;display:block;color:inherit!important;cursor:pointer;contain:layout style;-webkit-flex-shrink:0;flex-shrink:0}.cardContent-button,.textActionButton{cursor:pointer;vertical-align:middle;font-family:inherit}.card-nofocustransform{contain:layout style paint}.itemsContainer{display:-webkit-box;display:-webkit-flex;display:flex}.vertical-list,.vertical-wrap{display:-webkit-box;display:-webkit-flex;-webkit-box-direction:normal}.vertical-list{display:flex;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column;-webkit-flex-wrap:nowrap;flex-wrap:nowrap}.vertical-wrap{display:flex;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap}.cardImageContainer,.mediaSourceIndicator{display:-webkit-box;-webkit-box-align:center}.vertical-wrap.centered{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.cardScalable{position:relative;contain:layout style}.cardPadder-backdrop,.cardPadder-mixedBackdrop,.cardPadder-overflowBackdrop,.cardPadder-overflowSmallBackdrop,.cardPadder-smallBackdrop{padding-bottom:56.25%;contain:strict}.cardPadder-mixedSquare,.cardPadder-overflowSquare,.cardPadder-square,.overflowSquareCard-textCardPadder{padding-bottom:100%;contain:strict}.cardPadder-mixedPortrait,.cardPadder-overflowPortrait,.cardPadder-portrait,.overflowPortraitCard-textCardPadder{padding-bottom:150%;contain:strict}.cardPadder-banner{padding-bottom:18.5%;contain:strict}.cardBox{padding:0!important;margin:.9em;-webkit-transition:none;-o-transition:none;transition:none;border:0 solid transparent;contain:layout style}.cardBox-withfocuscontent-large{margin:.5em}@media (max-width:50em){.cardBox{margin:.4em}}.card-focuscontent-large{border:.4em solid transparent}.cardBox-focustransform{will-change:transform;-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.card:focus>.cardBox-focustransform{-webkit-transform:scale(1.18,1.18);transform:scale(1.18,1.18)}.cardBox-bottompadded{margin-bottom:1.8em!important}@media (max-width:50em){.cardBox-bottompadded{margin-bottom:1.2em!important}}.card:focus{position:relative!important;z-index:10!important}.btnCardOptions{position:absolute;bottom:.25em;right:0;margin:0!important;z-index:1}.mediaSourceIndicator{display:-webkit-flex;display:flex;position:absolute;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;top:.3em;left:.3em;text-align:center;vertical-align:middle;width:1.6em;height:1.6em;-webkit-border-radius:50%;border-radius:50%;color:#fff;background:#38c}.cardText,.innerCardFooter{overflow:hidden;text-align:left}.cardImageContainer{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;position:relative;-webkit-background-clip:content-box!important;background-clip:content-box!important;color:inherit;height:100%;contain:strict}.cardContent,.cardImage{position:absolute;right:0;top:0;left:0;bottom:0}.chapterCardImageContainer{background-color:#000;-webkit-border-radius:0;border-radius:0}.textCardImageContainer{background-color:#333}.cardContent{overflow:hidden;display:block;margin:0!important;height:100%;contain:strict}.cardContent-button{border:0!important;padding:0!important;color:inherit;width:100%;font-size:inherit}.cardContent-button:not(.defaultCardBackground){background-color:transparent}.visualCardBox .cardContent{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0}.cardContent-shadow{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37)}.cardImageContainer{display:-webkit-box;display:-webkit-flex;display:flex}.cardImage{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center bottom}.cardImage-img{max-height:100%;max-width:100%;min-height:70%;min-width:70%;margin:auto}.coveredImage-img{width:100%;height:100%}.coveredImage-noscale-img{max-height:none;max-width:none}.coveredImage{-webkit-background-size:100% 100%;background-size:100% 100%;background-position:center center}.coveredImage-noScale{-webkit-background-size:cover;background-size:cover}.cardFooter{padding:.3em .3em .5em;position:relative}.visualCardBox{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);-webkit-border-radius:.145em;border-radius:.145em}.innerCardFooter{background:rgba(0,0,0,.7);position:absolute;bottom:0;left:0;z-index:1;max-width:100%;color:#fff}.innerCardFooterClear{background-color:transparent}.fullInnerCardFooter{right:0}.cardText{padding:.06em .5em;white-space:nowrap;-o-text-overflow:ellipsis;text-overflow:ellipsis}.cardDefaultText,.cardTextCentered{text-align:center}.cardText-secondary{font-size:84%}.cardText-first{padding-top:.24em}.innerCardFooter>.cardText{padding:.3em .5em}.cardFooter-withlogo{padding-left:4em;position:relative}.cardFooterLogo{position:absolute;top:0;bottom:0;left:0;width:4.5em;-webkit-background-size:70% auto;background-size:70% auto;background-repeat:no-repeat;background-position:center center}.cardText-rightmargin{margin-right:2em}.cardDefaultText{white-space:normal}.textActionButton{background:0 0;border:0!important;padding:0!important;color:inherit;font-size:inherit}.textActionButton:hover{text-decoration:underline}.cardImageIcon{width:1em;height:1em;font-size:5em;color:inherit}.cardImageIcon-small{font-size:3em;margin-bottom:.1em}.cardIndicators{right:.225em;top:.225em;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;contain:layout style}.cardProgramAttributeIndicators{top:0;left:0;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;text-transform:uppercase;font-size:92%}.programAttributeIndicator{padding:.18em .5em;color:#fff;font-weight:500}.cardOverlayButton{color:rgba(255,255,255,.76)!important;margin:0;z-index:1;padding:.75em;font-size:88%}.cardOverlayButton-br{position:absolute;bottom:0;right:0}.cardOverlayButtonIcon{background-color:rgba(0,0,0,.7)!important;-webkit-border-radius:100em;border-radius:100em;width:1.5em!important;height:1.5em!important;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;font-size:1.66956521739130434em!important}.cardOverlayButton-centered{bottom:initial;right:initial;position:static;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;font-size:112%;margin:-1.3em 0 0 -1.3em;width:2.6em;height:2.6em;top:50%;left:50%;background-color:rgba(0,0,0,.5)!important;border:.06em solid rgba(255,255,255,.6);padding:.38em!important;color:rgba(255,255,255,.76);-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.cardOverlayButton-centered:hover{-webkit-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}.backdropCard,.bannerCard{width:100%}.smallBackdropCard,.squareCard{width:50%}.portraitCard{width:33.333333333333333333333333333333%}.mixedPortraitCard{width:12em}.mixedSquareCard{width:18em}.mixedBackdropCard{width:32em}@media (min-width:25em){.backdropCard{width:50%}}@media (min-width:31.25em){.portraitCard,.smallBackdropCard,.squareCard{width:33.333333333333333333333333333333%}}@media (min-width:43.75em){.portraitCard,.squareCard{width:25%}}@media (min-width:48.125em){.backdropCard{width:33.333333333333333333333333333333%}}@media (min-width:50em){.bannerCard{width:50%}.portraitCard,.squareCard{width:20%}.smallBackdropCard{width:25%}}@media (min-width:62.5em){.smallBackdropCard{width:20%}}@media (min-width:75em){.backdropCard{width:25%}.portraitCard,.squareCard{width:16.666666666666666666666666666667%}.bannerCard{width:33.333333333333333333333333333333%}.smallBackdropCard{width:16.666666666666666666666666666667%}}@media (min-width:87.5em){.portraitCard,.smallBackdropCard,.squareCard{width:14.285714285714285714285714285714%}}@media (min-width:100em){.smallBackdropCard{width:12.5%}.backdropCard{width:20%}.portraitCard,.squareCard{width:12.5%}}@media (min-width:120em){.portraitCard,.squareCard{width:11.111111111111111111111111111111%}}@media (min-width:131.25em){.bannerCard{width:25%}.portraitCard,.squareCard{width:10%}}@media (min-width:156.25em){.backdropCard{width:16.666666666666666666666666666667%}}.itemsContainer-tv>.backdropCard{width:25%}.itemsContainer-tv>.portraitCard,.itemsContainer-tv>.squareCard{width:16.666666666666666666666666666667%}@media (orientation:portrait){.overflowPortraitCard{width:42vw}.overflowBackdropCard,.overflowSmallBackdropCard{width:72vw}.overflowSquareCard{width:42vw}}@media (orientation:landscape){.overflowBackdropCard,.overflowSmallBackdropCard{width:23.3vw}.overflowPortraitCard,.overflowSquareCard{width:15.5vw}}@media (orientation:portrait) and (min-width:33.75em){.overflowSmallBackdropCard{width:30vw}}@media (orientation:landscape) and (min-width:50em){.overflowSmallBackdropCard{width:15.5vw}}@media (orientation:landscape) and (min-width:106.25em){.overflowBackdropCard{width:18.5vw}.overflowPortraitCard,.overflowSquareCard{width:11.6vw}}@media (orientation:portrait) and (min-width:25em){.overflowPortraitCard{width:31.5vw}}@media (orientation:portrait) and (min-width:33.75em){.overflowBackdropCard{width:64vw}.overflowSquareCard{width:31.5vw}}@media (orientation:portrait) and (min-width:40em){.overflowBackdropCard{width:56vw}}@media (orientation:portrait) and (min-width:47.5em){.overflowPortraitCard{width:23vw}.overflowBackdropCard{width:40vw}.overflowSquareCard{width:23vw}}@media (orientation:portrait) and (min-width:75em){.overflowPortraitCard,.overflowSquareCard{width:18vw}}@media (orientation:portrait) and (min-width:87.5em){.overflowPortraitCard,.overflowSquareCard{width:15vw}.overflowBackdropCard{width:30vw}}@media (orientation:portrait) and (min-width:112.5em){.overflowBackdropCard{width:23.5vw}}.itemsContainer-tv>.overflowBackdropCard{width:23.3vw}.overflowBackdropCard-textCard{width:15.5vw!important}.overflowBackdropCard-textCardPadder{padding-bottom:87.75%}.itemsContainer-tv>.overflowPortraitCard,.itemsContainer-tv>.overflowSquareCard{width:15.5vw}.itemsContainer-tv>.overflowSmallBackdropCard{width:18.9vw}.cardOverlayContainer{background:-webkit-radial-gradient(50% 50%,farthest-corner,rgba(30,30,30,.5) 50%,#2c2c2c 100%);background:-o-radial-gradient(50% 50%,farthest-corner,rgba(30,30,30,.5) 50%,#2c2c2c 100%);background:radial-gradient(farthest-corner at 50% 50%,rgba(30,30,30,.5) 50%,#2c2c2c 100%);opacity:0;-webkit-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s;position:absolute;top:0;left:0;bottom:0;right:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.card-hoverable :hover .cardOverlayContainer{opacity:1}.cardOverlayButton-hover{opacity:0;-webkit-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s;background:0 0;color:#fff!important;padding:.5em}.cardOverlayButtonIcon-hover{background:0 0!important}.card-hoverable:hover .cardOverlayButton-hover{opacity:1}.cardOverlayFab-primary{font-size:130%;padding:0;width:3em;height:3em;margin-top:-1.5em;margin-left:-1.5em;position:absolute;top:50%;left:50%}.cardOverlayFab-primary i{border:.07em solid rgba(255,255,255,.9);color:#fff}
\ No newline at end of file
+.card,.card:focus{font-weight:inherit!important}.card,.cardBox,.cardContent,.textActionButton{-webkit-tap-highlight-color:transparent;outline:0!important}button::-moz-focus-inner{padding:0;border:0}button{-webkit-border-fit:border!important}.card{border:0;font-size:inherit!important;font-family:inherit!important;text-transform:none;background:0 0!important;margin:0;padding:0;display:block;color:inherit!important;cursor:pointer;contain:layout style;-webkit-flex-shrink:0;flex-shrink:0}.cardContent-button,.textActionButton{cursor:pointer;vertical-align:middle;font-family:inherit}.card-nofocustransform{contain:layout style paint}.itemsContainer{display:-webkit-box;display:-webkit-flex;display:flex}.vertical-list,.vertical-wrap{display:-webkit-box;display:-webkit-flex;-webkit-box-direction:normal}.vertical-list{display:flex;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column;-webkit-flex-wrap:nowrap;flex-wrap:nowrap}.vertical-wrap{display:flex;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap}.cardImageContainer,.mediaSourceIndicator{display:-webkit-box;-webkit-box-align:center}.vertical-wrap.centered{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.cardScalable{position:relative;contain:layout style}.cardPadder-backdrop,.cardPadder-mixedBackdrop,.cardPadder-overflowBackdrop,.cardPadder-overflowSmallBackdrop,.cardPadder-smallBackdrop{padding-bottom:56.25%;contain:strict}.cardPadder-mixedSquare,.cardPadder-overflowSquare,.cardPadder-square,.overflowSquareCard-textCardPadder{padding-bottom:100%;contain:strict}.cardPadder-mixedPortrait,.cardPadder-overflowPortrait,.cardPadder-portrait,.overflowPortraitCard-textCardPadder{padding-bottom:150%;contain:strict}.cardPadder-banner{padding-bottom:18.5%;contain:strict}.cardBox{padding:0!important;margin:.4em;-webkit-transition:none;-o-transition:none;transition:none;border:0 solid transparent;contain:layout style}@media (min-width:50em){.cardBox{margin:1em}}.cardBox-withfocuscontent-large{margin:.5em}.card-focuscontent-large{border:.5em solid transparent}.cardBox-focustransform{will-change:transform;-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.card:focus>.cardBox-focustransform{-webkit-transform:scale(1.18,1.18);transform:scale(1.18,1.18)}.cardBox-bottompadded{margin-bottom:1.8em!important}@media (max-width:50em){.cardBox-bottompadded{margin-bottom:1.2em!important}}.card:focus{position:relative!important;z-index:10!important}.btnCardOptions{position:absolute;bottom:.25em;right:0;margin:0!important;z-index:1}.mediaSourceIndicator{display:-webkit-flex;display:flex;position:absolute;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;top:.3em;left:.3em;text-align:center;vertical-align:middle;width:1.6em;height:1.6em;-webkit-border-radius:50%;border-radius:50%;color:#fff;background:#38c}.cardText,.innerCardFooter{overflow:hidden;text-align:left}.cardImageContainer{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;position:relative;-webkit-background-clip:content-box!important;background-clip:content-box!important;color:inherit;height:100%;contain:strict}.cardContent,.cardImage{position:absolute;right:0;top:0;left:0;bottom:0}.chapterCardImageContainer{background-color:#000;-webkit-border-radius:0;border-radius:0}.textCardImageContainer{background-color:#333}.cardContent{overflow:hidden;display:block;margin:0!important;height:100%;contain:strict}.cardContent-button{border:0!important;padding:0!important;color:inherit;width:100%;font-size:inherit}.cardContent-button:not(.defaultCardBackground){background-color:transparent}.visualCardBox .cardContent{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0}.cardContent-shadow{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37)}.cardImageContainer{display:-webkit-box;display:-webkit-flex;display:flex}.cardImage{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center bottom}.cardImage-img{max-height:100%;max-width:100%;min-height:70%;min-width:70%;margin:auto}.coveredImage-img{width:100%;height:100%}.coveredImage-noscale-img{max-height:none;max-width:none}.coveredImage{-webkit-background-size:100% 100%;background-size:100% 100%;background-position:center center}.coveredImage-noScale{-webkit-background-size:cover;background-size:cover}.cardFooter{padding:.3em .3em .5em;position:relative}.visualCardBox{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);-webkit-border-radius:.145em;border-radius:.145em}.innerCardFooter{background:rgba(0,0,0,.7);position:absolute;bottom:0;left:0;z-index:1;max-width:100%;color:#fff}.innerCardFooterClear{background-color:transparent}.fullInnerCardFooter{right:0}.cardText{padding:.06em .5em;white-space:nowrap;-o-text-overflow:ellipsis;text-overflow:ellipsis}.cardDefaultText,.cardTextCentered{text-align:center}.cardText-secondary{font-size:86%}.cardText-first{padding-top:.24em}.innerCardFooter>.cardText{padding:.3em .5em}.cardFooter-withlogo{padding-left:4em;position:relative}.cardFooterLogo{position:absolute;top:0;bottom:0;left:0;width:4.5em;-webkit-background-size:70% auto;background-size:70% auto;background-repeat:no-repeat;background-position:center center}.cardText-rightmargin{margin-right:2em}.cardDefaultText{white-space:normal}.textActionButton{background:0 0;border:0!important;padding:0!important;color:inherit;font-size:inherit}.textActionButton:hover{text-decoration:underline}.cardImageIcon{width:1em;height:1em;font-size:5em;color:inherit}.cardImageIcon-small{font-size:3em;margin-bottom:.1em}.cardIndicators{right:.225em;top:.225em;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;contain:layout style}.cardProgramAttributeIndicators{top:0;left:0;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;text-transform:uppercase;font-size:92%}.programAttributeIndicator{padding:.18em .5em;color:#fff;font-weight:500}.cardOverlayButton{color:rgba(255,255,255,.76)!important;margin:0;z-index:1;padding:.75em;font-size:88%}.cardOverlayButton-br{position:absolute;bottom:0;right:0}.cardOverlayButtonIcon{background-color:rgba(0,0,0,.7)!important;-webkit-border-radius:100em;border-radius:100em;width:1.5em!important;height:1.5em!important;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;font-size:1.66956521739130434em!important}.cardOverlayButton-centered{bottom:initial;right:initial;position:static;position:absolute;display:-webkit-box;display:-webkit-flex;display:flex;font-size:112%;margin:-1.3em 0 0 -1.3em;width:2.6em;height:2.6em;top:50%;left:50%;background-color:rgba(0,0,0,.5)!important;border:.06em solid rgba(255,255,255,.6);padding:.38em!important;color:rgba(255,255,255,.76);-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.cardOverlayButton-centered:hover{-webkit-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}.backdropCard,.bannerCard{width:100%}.smallBackdropCard,.squareCard{width:50%}.portraitCard{width:33.333333333333333333333333333333%}.mixedPortraitCard{width:12em}.mixedSquareCard{width:18em}.mixedBackdropCard{width:32em}@media (min-width:25em){.backdropCard{width:50%}}@media (min-width:31.25em){.portraitCard,.smallBackdropCard,.squareCard{width:33.333333333333333333333333333333%}}@media (min-width:43.75em){.portraitCard,.squareCard{width:25%}}@media (min-width:48.125em){.backdropCard{width:33.333333333333333333333333333333%}}@media (min-width:50em){.bannerCard{width:50%}.portraitCard,.squareCard{width:20%}.smallBackdropCard{width:25%}}@media (min-width:62.5em){.smallBackdropCard{width:20%}}@media (min-width:75em){.backdropCard{width:25%}.portraitCard,.squareCard{width:16.666666666666666666666666666667%}.bannerCard{width:33.333333333333333333333333333333%}.smallBackdropCard{width:16.666666666666666666666666666667%}}@media (min-width:87.5em){.portraitCard,.smallBackdropCard,.squareCard{width:14.285714285714285714285714285714%}}@media (min-width:100em){.smallBackdropCard{width:12.5%}.backdropCard{width:20%}.portraitCard,.squareCard{width:12.5%}}@media (min-width:120em){.portraitCard,.squareCard{width:11.111111111111111111111111111111%}}@media (min-width:131.25em){.bannerCard{width:25%}.portraitCard,.squareCard{width:10%}}@media (min-width:156.25em){.backdropCard{width:16.666666666666666666666666666667%}}.itemsContainer-tv>.backdropCard{width:25%}.itemsContainer-tv>.portraitCard,.itemsContainer-tv>.squareCard{width:16.666666666666666666666666666667%}@media (orientation:portrait){.overflowPortraitCard{width:42vw}.overflowBackdropCard,.overflowSmallBackdropCard{width:72vw}.overflowSquareCard{width:42vw}}@media (orientation:landscape){.overflowBackdropCard,.overflowSmallBackdropCard{width:23.3vw}.overflowPortraitCard,.overflowSquareCard{width:15.5vw}}@media (orientation:portrait) and (min-width:33.75em){.overflowSmallBackdropCard{width:30vw}}@media (orientation:landscape) and (min-width:50em){.overflowSmallBackdropCard{width:15.5vw}}@media (orientation:landscape) and (min-width:106.25em){.overflowBackdropCard{width:18.5vw}.overflowPortraitCard,.overflowSquareCard{width:11.6vw}}@media (orientation:portrait) and (min-width:25em){.overflowPortraitCard{width:31.5vw}}@media (orientation:portrait) and (min-width:33.75em){.overflowBackdropCard{width:64vw}.overflowSquareCard{width:31.5vw}}@media (orientation:portrait) and (min-width:40em){.overflowBackdropCard{width:56vw}}@media (orientation:portrait) and (min-width:47.5em){.overflowPortraitCard{width:23vw}.overflowBackdropCard{width:40vw}.overflowSquareCard{width:23vw}}@media (orientation:portrait) and (min-width:75em){.overflowPortraitCard,.overflowSquareCard{width:18vw}}@media (orientation:portrait) and (min-width:87.5em){.overflowPortraitCard,.overflowSquareCard{width:15vw}.overflowBackdropCard{width:30vw}}@media (orientation:portrait) and (min-width:112.5em){.overflowBackdropCard{width:23.5vw}}.itemsContainer-tv>.overflowBackdropCard{width:23.3vw}.overflowBackdropCard-textCard{width:15.5vw!important}.overflowBackdropCard-textCardPadder{padding-bottom:87.75%}.itemsContainer-tv>.overflowPortraitCard,.itemsContainer-tv>.overflowSquareCard{width:15.5vw}.itemsContainer-tv>.overflowSmallBackdropCard{width:18.9vw}.cardOverlayContainer{background:-webkit-radial-gradient(50% 50%,farthest-corner,rgba(30,30,30,.5) 50%,#2c2c2c 100%);background:-o-radial-gradient(50% 50%,farthest-corner,rgba(30,30,30,.5) 50%,#2c2c2c 100%);background:radial-gradient(farthest-corner at 50% 50%,rgba(30,30,30,.5) 50%,#2c2c2c 100%);opacity:0;-webkit-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s;position:absolute;top:0;left:0;bottom:0;right:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.card-hoverable :hover .cardOverlayContainer{opacity:1}.cardOverlayButton-hover{opacity:0;-webkit-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s;background:0 0;color:#fff!important;padding:.5em}.cardOverlayButtonIcon-hover{background:0 0!important}.card-hoverable:hover .cardOverlayButton-hover{opacity:1}.cardOverlayFab-primary{font-size:130%;padding:0;width:3em;height:3em;margin-top:-1.5em;margin-left:-1.5em;position:absolute;top:50%;left:50%}.cardOverlayFab-primary i{border:.07em solid rgba(255,255,255,.9);color:#fff}
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fullscreen/fullscreen-doubleclick.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js
similarity index 100%
rename from MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fullscreen/fullscreen-doubleclick.js
rename to MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/strings/en-us.json b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/strings/en-us.json
index 9b82ee106d..3729867898 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/strings/en-us.json
+++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/strings/en-us.json
@@ -306,7 +306,8 @@
"ConfirmDeleteItems": "Deleting these items will delete them from both the file system and your media library. Are you sure you wish to continue?",
"PleaseRestartServerName": "Please restart Emby Server - {0}.",
"LabelSyncJobName": "Sync job name:",
- "SyncJobCreated": "Sync job created",
+ "SyncingDots": "Syncing...",
+ "ConvertingDots": "Converting...",
"LabelQuality": "Quality:",
"LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support offline downloading.",
"DownloadingDots": "Downloading...",
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/sync.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/sync.js
index 72c05e1abd..eb76e14715 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/sync.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/sync.js
@@ -1 +1 @@
-define(["apphost","globalize","connectionManager","layoutManager","focusManager","scrollHelper","appSettings","registrationServices","dialogHelper","paper-icon-button-light","formDialogStyle"],function(appHost,globalize,connectionManager,layoutManager,focusManager,scrollHelper,appSettings,registrationServices,dialogHelper){"use strict";function submitJob(dlg,apiClient,userId,syncOptions,form){if(!userId)throw new Error("userId cannot be null");if(!syncOptions)throw new Error("syncOptions cannot be null");if(!form)throw new Error("form cannot be null");var selectSyncTarget=form.querySelector("#selectSyncTarget"),target=selectSyncTarget?selectSyncTarget.value:null;if(!target)return require(["toast"],function(toast){toast(globalize.translate("sharedcomponents#PleaseSelectDeviceToSyncTo"))}),!1;var options={userId:userId,TargetId:target,ParentId:syncOptions.ParentId,Category:syncOptions.Category};return setJobValues(options,form),syncOptions.items&&syncOptions.items.length&&(options.ItemIds=(syncOptions.items||[]).map(function(i){return i.Id||i}).join(",")),apiClient.ajax({type:"POST",url:apiClient.getUrl("Sync/Jobs"),data:JSON.stringify(options),contentType:"application/json",dataType:"json"}).then(function(){dialogHelper.close(dlg),require(["toast"],function(toast){showSubmissionToast(target,apiClient),"download"===syncOptions.mode&&syncNow()})}),!0}function showSubmissionToast(targetId,apiClient){require(["toast"],function(toast){toast(targetId===apiClient.deviceId()?globalize.translate("sharedcomponents#DownloadingDots"):globalize.translate("sharedcomponents#SyncJobCreated"))})}function syncNow(){require(["localsync"],function(localSync){localSync.sync()})}function submitQuickSyncJob(apiClient,userId,targetId,syncOptions){if(!userId)throw new Error("userId cannot be null");if(!syncOptions)throw new Error("syncOptions cannot be null");if(!targetId)throw new Error("targetId cannot be null");var options={userId:userId,TargetId:targetId,ParentId:syncOptions.ParentId,Category:syncOptions.Category,Quality:syncOptions.Quality,Bitrate:syncOptions.Bitrate};return syncOptions.items&&syncOptions.items.length&&(options.ItemIds=(syncOptions.items||[]).map(function(i){return i.Id||i}).join(",")),apiClient.ajax({type:"POST",url:apiClient.getUrl("Sync/Jobs"),data:JSON.stringify(options),contentType:"application/json",dataType:"json"}).then(function(){require(["toast"],function(toast){showSubmissionToast(targetId,apiClient),"download"===syncOptions.mode&&syncNow()})})}function setJobValues(job,form){var txtBitrate=form.querySelector("#txtBitrate"),bitrate=txtBitrate?txtBitrate.value:null;bitrate&&(bitrate=1e6*parseFloat(bitrate)),job.Bitrate=bitrate;var selectQuality=form.querySelector("#selectQuality");selectQuality&&(job.Quality=selectQuality.value,appSettings.set("sync-lastquality",job.Quality||""));var selectProfile=form.querySelector("#selectProfile");selectProfile&&(job.Profile=selectProfile.value);var txtItemLimit=form.querySelector("#txtItemLimit");txtItemLimit&&(job.ItemLimit=txtItemLimit.value||null);var chkSyncNewContent=form.querySelector("#chkSyncNewContent");chkSyncNewContent&&(job.SyncNewContent=chkSyncNewContent.checked);var chkUnwatchedOnly=form.querySelector("#chkUnwatchedOnly");chkUnwatchedOnly&&(job.UnwatchedOnly=chkUnwatchedOnly.checked)}function renderForm(options){return new Promise(function(resolve,reject){require(["emby-checkbox","emby-input","emby-select"],function(){renderFormInternal(options,connectionManager.deviceId(),resolve)})})}function renderFormInternal(options,defaultTargetId,resolve){var elem=options.elem,dialogOptions=options.dialogOptions,targets=dialogOptions.Targets,html="",mode=options.mode,targetContainerClass="download"===mode?" hide":"",syncTargetLabel="convert"===mode?globalize.translate("sharedcomponents#LabelConvertTo"):globalize.translate("sharedcomponents#LabelSyncTo");options.readOnlySyncTarget?(html+='',html+=' ',html+="
"):(html+='',html+='
',html+=targets.map(function(t){return"'+t.Name+" "}).join(""),html+=" ",targets.length||(html+='
'+globalize.translate("sharedcomponents#LabelSyncNoTargetsHelp")+"
"),appHost.supports("externallinks")&&(html+='
"),html+="
"),html+='',html+='
',html+=" ",html+='
',html+="
",html+='',html+='
',html+=" ",html+='
',html+="
",html+='',html+=' ',html+="
",-1!==dialogOptions.Options.indexOf("UnwatchedOnly")&&(html+='',html+="
",html+=' ',html+="convert"===mode?""+globalize.translate("sharedcomponents#ConvertUnwatchedVideosOnly")+" ":""+globalize.translate("sharedcomponents#SyncUnwatchedVideosOnly")+" ",html+=" ",html+="convert"===mode?'
'+globalize.translate("sharedcomponents#ConvertUnwatchedVideosOnlyHelp")+"
":'
'+globalize.translate("sharedcomponents#SyncUnwatchedVideosOnlyHelp")+"
",html+="
"),-1!==dialogOptions.Options.indexOf("SyncNewContent")&&(html+='',html+="
",html+=' ',html+="convert"===mode?""+globalize.translate("sharedcomponents#AutomaticallyConvertNewContent")+" ":""+globalize.translate("sharedcomponents#AutomaticallySyncNewContent")+" ",html+=" ",html+="convert"===mode?'
'+globalize.translate("sharedcomponents#AutomaticallyConvertNewContentHelp")+"
":'
'+globalize.translate("sharedcomponents#AutomaticallySyncNewContentHelp")+"
",html+="
"),-1!==dialogOptions.Options.indexOf("ItemLimit")&&(html+='"),elem.innerHTML=html;var selectSyncTarget=elem.querySelector("#selectSyncTarget");selectSyncTarget&&(selectSyncTarget.addEventListener("change",function(){loadQualityOptions(elem,this.value,options.dialogOptionsFn).then(resolve)}),selectSyncTarget.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectProfile=elem.querySelector("#selectProfile");selectProfile&&(selectProfile.addEventListener("change",function(){onProfileChange(elem,this.value)}),dialogOptions.ProfileOptions.length&&selectProfile.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectQuality=elem.querySelector("#selectQuality");selectQuality&&(selectQuality.addEventListener("change",function(){onQualityChange(elem,this.value)}),selectQuality.dispatchEvent(new CustomEvent("change",{bubbles:!0}))),setTimeout(function(){focusManager.autoFocus(elem)},100)}function showWifiMessage(){require(["dialog","appRouter"],function(dialog,appRouter){var options={title:globalize.translate("sharedcomponents#HeaderWaitingForWifi"),text:globalize.translate("sharedcomponents#WifiRequiredToDownload")},items=[];items.push({name:options.confirmText||globalize.translate("sharedcomponents#ButtonOk"),id:"ok",type:"submit"}),items.push({name:options.cancelText||globalize.translate("sharedcomponents#HeaderDownloadSettings"),id:"downloadsettings",type:"cancel"}),options.buttons=items,dialog(options).then(function(result){return"ok"===result?Promise.resolve():"downloadsettings"===result?(appRouter.show(appRouter.getRouteUrl("downloadsettings")),Promise.resolve()):Promise.reject()})})}function validateNetwork(){switch(navigator.connection?navigator.connection.type:null){case"cellular":case"bluetooth":return showWifiMessage(),!1;default:return!0}}function showSyncMenu(options){return"download"===options.mode&&appSettings.syncOnlyOnWifi()&&!validateNetwork()?Promise.reject():registrationServices.validateFeature("sync").then(function(){return showSyncMenuInternal(options)})}function enableAutoSync(options){if("download"!==options.mode)return!1;var firstItem=(options.items||[])[0]||{};return"Audio"===firstItem.Type||("MusicAlbum"===firstItem.Type||("MusicArtist"===firstItem.Type||("MusicGenre"===firstItem.Type||"Playlist"===firstItem.Type&&"Audio"===firstItem.MediaType)))}function showSyncMenuInternal(options){var apiClient=connectionManager.getApiClient(options.serverId),userId=apiClient.getCurrentUserId();if(enableAutoSync(options))return submitQuickSyncJob(apiClient,userId,apiClient.deviceId(),{items:options.items,Quality:"custom",Bitrate:appSettings.maxStaticMusicBitrate()});var dialogOptionsFn=getTargetDialogOptionsFn(apiClient,{UserId:userId,ItemIds:(options.items||[]).map(function(i){return i.Id||i}).join(","),ParentId:options.ParentId,Category:options.Category,IncludeProviders:"convert"===options.mode?"ConvertSyncProvider":null,ExcludeProviders:"convert"===options.mode?null:"ConvertSyncProvider"});return dialogOptionsFn().then(function(dialogOptions){currentDialogOptions=dialogOptions;var dlgElementOptions={removeOnClose:!0,scrollY:!1,autoFocus:!1};layoutManager.tv?dlgElementOptions.size="fullscreen":dlgElementOptions.size="small";var dlg=dialogHelper.createDialog(dlgElementOptions);dlg.classList.add("formDialog");var html="";html+='",html+='",dlg.innerHTML=html;var submitted=!1;dlg.querySelector("form").addEventListener("submit",function(e){return submitted=submitJob(dlg,apiClient,userId,options,this),e.preventDefault(),!1}),dlg.querySelector(".btnCancel").addEventListener("click",function(){dialogHelper.close(dlg)}),layoutManager.tv&&scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"),!1);var promise=dialogHelper.open(dlg);return renderForm({elem:dlg.querySelector(".formFields"),dialogOptions:dialogOptions,dialogOptionsFn:dialogOptionsFn,mode:options.mode}),promise.then(function(){return layoutManager.tv&&scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"),!1),submitted?Promise.resolve():Promise.reject()})})}function getTargetDialogOptionsFn(apiClient,query){return function(targetId){return query.TargetId=targetId,apiClient.getJSON(apiClient.getUrl("Sync/Options",query))}}function setQualityFieldVisible(form,visible){var fldQuality=form.querySelector(".fldQuality"),selectQuality=form.querySelector("#selectQuality");visible?(fldQuality&&fldQuality.classList.remove("hide"),selectQuality&&selectQuality.removeAttribute("required")):(fldQuality&&fldQuality.classList.add("hide"),selectQuality&&selectQuality.removeAttribute("required"))}function onProfileChange(form,profileId){var options=currentDialogOptions||{},profileOptions=options.ProfileOptions||[];if(profileOptions.length){var option=profileOptions.filter(function(o){return o.Id===profileId})[0],qualityOptions=options.QualityOptions||[];option?(form.querySelector(".profileDescription").innerHTML=option.Description||"",setQualityFieldVisible(form,qualityOptions.length>0&&option.EnableQualityOptions&&-1!==options.Options.indexOf("Quality"))):(form.querySelector(".profileDescription").innerHTML="",setQualityFieldVisible(form,qualityOptions.length>0&&-1!==options.Options.indexOf("Quality")))}}function onQualityChange(form,qualityId){var options=currentDialogOptions||{},option=(options.QualityOptions||[]).filter(function(o){return o.Id===qualityId})[0],qualityDescription=form.querySelector(".qualityDescription");qualityDescription.innerHTML=option?option.Description||"":"";var fldBitrate=form.querySelector(".fldBitrate"),txtBitrate=form.querySelector("#txtBitrate");"custom"===qualityId?(fldBitrate&&fldBitrate.classList.remove("hide"),txtBitrate&&txtBitrate.setAttribute("required","required")):(fldBitrate&&fldBitrate.classList.add("hide"),txtBitrate&&txtBitrate.removeAttribute("required"))}function renderTargetDialogOptions(form,options){currentDialogOptions=options;var fldProfile=form.querySelector(".fldProfile"),selectProfile=form.querySelector("#selectProfile");options.ProfileOptions.length&&-1!==options.Options.indexOf("Profile")?(fldProfile&&fldProfile.classList.remove("hide"),selectProfile&&selectProfile.setAttribute("required","required")):(fldProfile&&fldProfile.classList.add("hide"),selectProfile&&selectProfile.removeAttribute("required")),setQualityFieldVisible(form,options.QualityOptions.length>0),selectProfile&&(selectProfile.innerHTML=options.ProfileOptions.map(function(o){var selectedAttribute=o.IsDefault?' selected="selected"':"";return'"+o.Name+" "}).join(""),selectProfile.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectQuality=form.querySelector("#selectQuality");if(selectQuality){selectQuality.innerHTML=options.QualityOptions.map(function(o){var selectedAttribute=o.IsDefault?' selected="selected"':"";return'"+o.Name+" "}).join("");var lastQuality=appSettings.get("sync-lastquality");lastQuality&&options.QualityOptions.filter(function(i){return i.Id===lastQuality}).length&&(selectQuality.value=lastQuality),selectQuality.dispatchEvent(new CustomEvent("change",{bubbles:!0}))}}function loadQualityOptions(form,targetId,dialogOptionsFn){return dialogOptionsFn(targetId).then(function(options){return renderTargetDialogOptions(form,options)})}var currentDialogOptions;return{showMenu:showSyncMenu,renderForm:renderForm,setJobValues:setJobValues}});
\ No newline at end of file
+define(["apphost","globalize","connectionManager","layoutManager","focusManager","scrollHelper","appSettings","registrationServices","dialogHelper","paper-icon-button-light","formDialogStyle"],function(appHost,globalize,connectionManager,layoutManager,focusManager,scrollHelper,appSettings,registrationServices,dialogHelper){"use strict";function submitJob(dlg,apiClient,userId,syncOptions,form){if(!userId)throw new Error("userId cannot be null");if(!syncOptions)throw new Error("syncOptions cannot be null");if(!form)throw new Error("form cannot be null");var selectSyncTarget=form.querySelector("#selectSyncTarget"),target=selectSyncTarget?selectSyncTarget.value:null;if(!target)return require(["toast"],function(toast){toast(globalize.translate("sharedcomponents#PleaseSelectDeviceToSyncTo"))}),!1;var options={userId:userId,TargetId:target,ParentId:syncOptions.ParentId,Category:syncOptions.Category};return setJobValues(options,form),syncOptions.items&&syncOptions.items.length&&(options.ItemIds=(syncOptions.items||[]).map(function(i){return i.Id||i}).join(",")),apiClient.ajax({type:"POST",url:apiClient.getUrl("Sync/Jobs"),data:JSON.stringify(options),contentType:"application/json",dataType:"json"}).then(function(){dialogHelper.close(dlg),require(["toast"],function(toast){showSubmissionToast(target,apiClient),"download"===syncOptions.mode&&syncNow()})}),!0}function showSubmissionToast(targetId,apiClient){require(["toast"],function(toast){toast(targetId===apiClient.deviceId()?globalize.translate("sharedcomponents#DownloadingDots"):globalize.translate("sharedcomponents#SyncingDots"))})}function syncNow(){require(["localsync"],function(localSync){localSync.sync()})}function submitQuickSyncJob(apiClient,userId,targetId,syncOptions){if(!userId)throw new Error("userId cannot be null");if(!syncOptions)throw new Error("syncOptions cannot be null");if(!targetId)throw new Error("targetId cannot be null");var options={userId:userId,TargetId:targetId,ParentId:syncOptions.ParentId,Category:syncOptions.Category,Quality:syncOptions.Quality,Bitrate:syncOptions.Bitrate};return syncOptions.items&&syncOptions.items.length&&(options.ItemIds=(syncOptions.items||[]).map(function(i){return i.Id||i}).join(",")),apiClient.ajax({type:"POST",url:apiClient.getUrl("Sync/Jobs"),data:JSON.stringify(options),contentType:"application/json",dataType:"json"}).then(function(){require(["toast"],function(toast){showSubmissionToast(targetId,apiClient),"download"===syncOptions.mode&&syncNow()})})}function setJobValues(job,form){var txtBitrate=form.querySelector("#txtBitrate"),bitrate=txtBitrate?txtBitrate.value:null;bitrate&&(bitrate=1e6*parseFloat(bitrate)),job.Bitrate=bitrate;var selectQuality=form.querySelector("#selectQuality");selectQuality&&(job.Quality=selectQuality.value,appSettings.set("sync-lastquality",job.Quality||""));var selectProfile=form.querySelector("#selectProfile");selectProfile&&(job.Profile=selectProfile.value);var txtItemLimit=form.querySelector("#txtItemLimit");txtItemLimit&&(job.ItemLimit=txtItemLimit.value||null);var chkSyncNewContent=form.querySelector("#chkSyncNewContent");chkSyncNewContent&&(job.SyncNewContent=chkSyncNewContent.checked);var chkUnwatchedOnly=form.querySelector("#chkUnwatchedOnly");chkUnwatchedOnly&&(job.UnwatchedOnly=chkUnwatchedOnly.checked)}function renderForm(options){return new Promise(function(resolve,reject){require(["emby-checkbox","emby-input","emby-select"],function(){renderFormInternal(options,connectionManager.deviceId(),resolve)})})}function renderFormInternal(options,defaultTargetId,resolve){var elem=options.elem,dialogOptions=options.dialogOptions,targets=dialogOptions.Targets,html="",mode=options.mode,targetContainerClass="download"===mode?" hide":"",syncTargetLabel="convert"===mode?globalize.translate("sharedcomponents#LabelConvertTo"):globalize.translate("sharedcomponents#LabelSyncTo");options.readOnlySyncTarget?(html+='',html+=' ',html+="
"):(html+='',html+='
',html+=targets.map(function(t){return"'+t.Name+" "}).join(""),html+=" ",targets.length||(html+='
'+globalize.translate("sharedcomponents#LabelSyncNoTargetsHelp")+"
"),appHost.supports("externallinks")&&(html+='
"),html+="
"),html+='',html+='
',html+=" ",html+='
',html+="
",html+='',html+='
',html+=" ",html+='
',html+="
",html+='',html+=' ',html+="
",-1!==dialogOptions.Options.indexOf("UnwatchedOnly")&&(html+='',html+="
",html+=' ',html+="convert"===mode?""+globalize.translate("sharedcomponents#ConvertUnwatchedVideosOnly")+" ":""+globalize.translate("sharedcomponents#SyncUnwatchedVideosOnly")+" ",html+=" ",html+="convert"===mode?'
'+globalize.translate("sharedcomponents#ConvertUnwatchedVideosOnlyHelp")+"
":'
'+globalize.translate("sharedcomponents#SyncUnwatchedVideosOnlyHelp")+"
",html+="
"),-1!==dialogOptions.Options.indexOf("SyncNewContent")&&(html+='',html+="
",html+=' ',html+="convert"===mode?""+globalize.translate("sharedcomponents#AutomaticallyConvertNewContent")+" ":""+globalize.translate("sharedcomponents#AutomaticallySyncNewContent")+" ",html+=" ",html+="convert"===mode?'
'+globalize.translate("sharedcomponents#AutomaticallyConvertNewContentHelp")+"
":'
'+globalize.translate("sharedcomponents#AutomaticallySyncNewContentHelp")+"
",html+="
"),-1!==dialogOptions.Options.indexOf("ItemLimit")&&(html+='"),elem.innerHTML=html;var selectSyncTarget=elem.querySelector("#selectSyncTarget");selectSyncTarget&&(selectSyncTarget.addEventListener("change",function(){loadQualityOptions(elem,this.value,options.dialogOptionsFn).then(resolve)}),selectSyncTarget.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectProfile=elem.querySelector("#selectProfile");selectProfile&&(selectProfile.addEventListener("change",function(){onProfileChange(elem,this.value)}),dialogOptions.ProfileOptions.length&&selectProfile.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectQuality=elem.querySelector("#selectQuality");selectQuality&&(selectQuality.addEventListener("change",function(){onQualityChange(elem,this.value)}),selectQuality.dispatchEvent(new CustomEvent("change",{bubbles:!0}))),setTimeout(function(){focusManager.autoFocus(elem)},100)}function showWifiMessage(){require(["dialog","appRouter"],function(dialog,appRouter){var options={title:globalize.translate("sharedcomponents#HeaderWaitingForWifi"),text:globalize.translate("sharedcomponents#WifiRequiredToDownload")},items=[];items.push({name:options.confirmText||globalize.translate("sharedcomponents#ButtonOk"),id:"ok",type:"submit"}),items.push({name:options.cancelText||globalize.translate("sharedcomponents#HeaderDownloadSettings"),id:"downloadsettings",type:"cancel"}),options.buttons=items,dialog(options).then(function(result){return"ok"===result?Promise.resolve():"downloadsettings"===result?(appRouter.show(appRouter.getRouteUrl("downloadsettings")),Promise.resolve()):Promise.reject()})})}function validateNetwork(){switch(navigator.connection?navigator.connection.type:null){case"cellular":case"bluetooth":return showWifiMessage(),!1;default:return!0}}function showSyncMenu(options){return"download"===options.mode&&appSettings.syncOnlyOnWifi()&&!validateNetwork()?Promise.reject():registrationServices.validateFeature("sync").then(function(){return showSyncMenuInternal(options)})}function enableAutoSync(options){if("download"!==options.mode)return!1;var firstItem=(options.items||[])[0]||{};return"Audio"===firstItem.Type||("MusicAlbum"===firstItem.Type||("MusicArtist"===firstItem.Type||("MusicGenre"===firstItem.Type||"Playlist"===firstItem.Type&&"Audio"===firstItem.MediaType)))}function showSyncMenuInternal(options){var apiClient=connectionManager.getApiClient(options.serverId),userId=apiClient.getCurrentUserId();if(enableAutoSync(options))return submitQuickSyncJob(apiClient,userId,apiClient.deviceId(),{items:options.items,Quality:"custom",Bitrate:appSettings.maxStaticMusicBitrate()});var dialogOptionsFn=getTargetDialogOptionsFn(apiClient,{UserId:userId,ItemIds:(options.items||[]).map(function(i){return i.Id||i}).join(","),ParentId:options.ParentId,Category:options.Category,IncludeProviders:"convert"===options.mode?"ConvertSyncProvider":null,ExcludeProviders:"convert"===options.mode?null:"ConvertSyncProvider"});return dialogOptionsFn().then(function(dialogOptions){currentDialogOptions=dialogOptions;var dlgElementOptions={removeOnClose:!0,scrollY:!1,autoFocus:!1};layoutManager.tv?dlgElementOptions.size="fullscreen":dlgElementOptions.size="small";var dlg=dialogHelper.createDialog(dlgElementOptions);dlg.classList.add("formDialog");var html="";html+='",html+='",dlg.innerHTML=html;var submitted=!1;dlg.querySelector("form").addEventListener("submit",function(e){return submitted=submitJob(dlg,apiClient,userId,options,this),e.preventDefault(),!1}),dlg.querySelector(".btnCancel").addEventListener("click",function(){dialogHelper.close(dlg)}),layoutManager.tv&&scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"),!1);var promise=dialogHelper.open(dlg);return renderForm({elem:dlg.querySelector(".formFields"),dialogOptions:dialogOptions,dialogOptionsFn:dialogOptionsFn,mode:options.mode}),promise.then(function(){return layoutManager.tv&&scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"),!1),submitted?Promise.resolve():Promise.reject()})})}function getTargetDialogOptionsFn(apiClient,query){return function(targetId){return query.TargetId=targetId,apiClient.getJSON(apiClient.getUrl("Sync/Options",query))}}function setQualityFieldVisible(form,visible){var fldQuality=form.querySelector(".fldQuality"),selectQuality=form.querySelector("#selectQuality");visible?(fldQuality&&fldQuality.classList.remove("hide"),selectQuality&&selectQuality.removeAttribute("required")):(fldQuality&&fldQuality.classList.add("hide"),selectQuality&&selectQuality.removeAttribute("required"))}function onProfileChange(form,profileId){var options=currentDialogOptions||{},profileOptions=options.ProfileOptions||[];if(profileOptions.length){var option=profileOptions.filter(function(o){return o.Id===profileId})[0],qualityOptions=options.QualityOptions||[];option?(form.querySelector(".profileDescription").innerHTML=option.Description||"",setQualityFieldVisible(form,qualityOptions.length>0&&option.EnableQualityOptions&&-1!==options.Options.indexOf("Quality"))):(form.querySelector(".profileDescription").innerHTML="",setQualityFieldVisible(form,qualityOptions.length>0&&-1!==options.Options.indexOf("Quality")))}}function onQualityChange(form,qualityId){var options=currentDialogOptions||{},option=(options.QualityOptions||[]).filter(function(o){return o.Id===qualityId})[0],qualityDescription=form.querySelector(".qualityDescription");qualityDescription.innerHTML=option?option.Description||"":"";var fldBitrate=form.querySelector(".fldBitrate"),txtBitrate=form.querySelector("#txtBitrate");"custom"===qualityId?(fldBitrate&&fldBitrate.classList.remove("hide"),txtBitrate&&txtBitrate.setAttribute("required","required")):(fldBitrate&&fldBitrate.classList.add("hide"),txtBitrate&&txtBitrate.removeAttribute("required"))}function renderTargetDialogOptions(form,options){currentDialogOptions=options;var fldProfile=form.querySelector(".fldProfile"),selectProfile=form.querySelector("#selectProfile");options.ProfileOptions.length&&-1!==options.Options.indexOf("Profile")?(fldProfile&&fldProfile.classList.remove("hide"),selectProfile&&selectProfile.setAttribute("required","required")):(fldProfile&&fldProfile.classList.add("hide"),selectProfile&&selectProfile.removeAttribute("required")),setQualityFieldVisible(form,options.QualityOptions.length>0),selectProfile&&(selectProfile.innerHTML=options.ProfileOptions.map(function(o){var selectedAttribute=o.IsDefault?' selected="selected"':"";return'"+o.Name+" "}).join(""),selectProfile.dispatchEvent(new CustomEvent("change",{bubbles:!0})));var selectQuality=form.querySelector("#selectQuality");if(selectQuality){selectQuality.innerHTML=options.QualityOptions.map(function(o){var selectedAttribute=o.IsDefault?' selected="selected"':"";return'"+o.Name+" "}).join("");var lastQuality=appSettings.get("sync-lastquality");lastQuality&&options.QualityOptions.filter(function(i){return i.Id===lastQuality}).length&&(selectQuality.value=lastQuality),selectQuality.dispatchEvent(new CustomEvent("change",{bubbles:!0}))}}function loadQualityOptions(form,targetId,dialogOptionsFn){return dialogOptionsFn(targetId).then(function(options){return renderTargetDialogOptions(form,options)})}var currentDialogOptions;return{showMenu:showSyncMenu,renderForm:renderForm,setJobValues:setJobValues}});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/syncjoblist.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/syncjoblist.js
index 666799c612..0208990a9a 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/syncjoblist.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/sync/syncjoblist.js
@@ -1 +1 @@
-define(["serverNotifications","events","loading","connectionManager","imageLoader","dom","globalize","registrationServices","layoutManager","listViewStyle"],function(serverNotifications,events,loading,connectionManager,imageLoader,dom,globalize,registrationServices,layoutManager){"use strict";function onSyncJobsUpdated(e,apiClient,data){renderList(this,data,apiClient)}function refreshList(listInstance,jobs){for(var i=0,length=jobs.length;i0&&progress<100&&(progress=progress.toFixed(1)),html+=progress+"%"}return html}function getSyncJobHtml(listInstance,job,apiClient){var html="",tagName=layoutManager.tv?"button":"div",typeAttribute="button"===tagName?' type="button"':"",listItemClass="listItem listItem-border";layoutManager.tv&&(listItemClass+=" listItem-button listItem-focusscale",listItemClass+=" btnJobMenu");var canEdit=(job.ItemCount||1)>1||"Queued"===job.Status;html+="<"+tagName+typeAttribute+' class="'+listItemClass+'" data-canedit="'+canEdit+'" data-id="'+job.Id+'" data-status="'+job.Status+'">';var imgUrl;job.PrimaryImageItemId&&(imgUrl=apiClient.getImageUrl(job.PrimaryImageItemId,{type:"Primary",width:80,tag:job.PrimaryImageTag,minScale:1.5})),imgUrl?(html+='',html+="
"):html+='file_download ';var textLines=[],name=job.Name;job.ParentName&&(name+=" - "+job.ParentName),textLines.push(name),1===job.ItemCount||textLines.push(globalize.translate("sharedcomponents#ItemCount",job.ItemCount)),html+='';for(var i=0,length=textLines.length;i
',html+=textLines[i],html+=""):(html+='',html+=textLines[i],html+="
");return html+='',html+=getProgressText(job),html+="
",html+=" ",layoutManager.tv||(html+=canEdit?'':'delete '),html+=""+tagName+">"}function renderList(listInstance,jobs,apiClient){if((new Date).getTime()-listInstance.lastDataLoad<6e4)return void refreshList(listInstance,jobs);listInstance.lastDataLoad=(new Date).getTime();for(var html="",lastTargetName="",mode=listInstance.options.mode,showTargetName="download"!==mode,hasOpenSection=!1,i=0,length=jobs.length;i",html+=" ",hasOpenSection=!1),lastTargetName=targetName,html+='',html+='
',html+='
'+targetName+" ",html+="",html+='
',hasOpenSection=!0)}html+=getSyncJobHtml(listInstance,job,apiClient)}hasOpenSection&&(html+="
",html+="
");var elem=listInstance.options.element.querySelector(".syncJobListContent");html||(html="download"===mode?''+globalize.translate("sharedcomponents#MessageNoDownloadsFound")+"
":''+globalize.translate("sharedcomponents#MessageNoSyncJobsFound")+"
"),elem.innerHTML=html,imageLoader.lazyChildren(elem)}function fetchData(listInstance){listInstance.lastDataLoad=0,loading.show();var options={},apiClient=getApiClient(listInstance);return listInstance.options.userId&&(options.UserId=listInstance.options.userId),"download"===listInstance.options.mode&&(options.TargetId=apiClient.deviceId()),apiClient.getJSON(apiClient.getUrl("Sync/Jobs",options)).then(function(response){renderList(listInstance,response.Items,apiClient),loading.hide()})}function startListening(listInstance){var startParams="0,1500",apiClient=getApiClient(listInstance);listInstance.options.userId&&(startParams+=","+listInstance.options.userId),"download"===listInstance.options.mode?startParams+=","+apiClient.deviceId():!1===listInstance.options.enableRemoteSyncManagement&&(startParams+=",true"),apiClient.sendMessage("SyncJobsStart",startParams)}function stopListening(listInstance){getApiClient(listInstance).sendMessage("SyncJobsStop","")}function getApiClient(listInstance){return connectionManager.getApiClient(listInstance.options.serverId)}function showJobMenu(listInstance,elem){var item=dom.parentWithClass(elem,"listItem"),jobId=item.getAttribute("data-id"),menuItems=(item.getAttribute("data-status"),[]);"true"===item.getAttribute("data-canedit")&&menuItems.push({name:globalize.translate("sharedcomponents#Edit"),id:"edit"});var txt=globalize.translate("sharedcomponents#RemoveDownload");menuItems.push({name:txt,id:"cancel"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:menuItems,positionTo:elem,callback:function(id){switch(id){case"delete":case"cancel":cancelJob(listInstance,jobId);break;case"edit":showJobEditor(listInstance,elem)}}})})}function onElementClick(e){var listInstance=this,btnJobMenu=dom.parentWithClass(e.target,"btnJobMenu");if(btnJobMenu)return void showJobMenu(listInstance,btnJobMenu);var btnCancelJob=dom.parentWithClass(e.target,"btnCancelJob");if(btnCancelJob){var listItem=dom.parentWithClass(btnCancelJob,"listItem");if(listItem){cancelJob(listInstance,listItem.getAttribute("data-id"))}}else showJobEditor(listInstance,e.target)}function showJobEditor(listInstance,elem){var listItem=dom.parentWithClass(elem,"listItem");if(listItem&&"true"===listItem.getAttribute("data-canedit")){var jobId=listItem.getAttribute("data-id");require(["syncJobEditor"],function(syncJobEditor){syncJobEditor.show({serverId:listInstance.options.serverId,jobId:jobId,mode:listInstance.options.mode}).then(function(){fetchData(listInstance)})})}}function syncJobList(options){this.options=options;var onSyncJobsUpdatedHandler=onSyncJobsUpdated.bind(this);this.onSyncJobsUpdatedHandler=onSyncJobsUpdatedHandler,events.on(serverNotifications,"SyncJobs",onSyncJobsUpdatedHandler);var onClickHandler=onElementClick.bind(this);options.element.addEventListener("click",onClickHandler),this.onClickHandler=onClickHandler,options.element.innerHTML='
',fetchData(this),startListening(this),initSupporterInfo(options.element,getApiClient(this))}function showSupporterInfo(context){var html='';html+="",html+=globalize.translate("sharedcomponents#HeaderSyncRequiresSub"),html+="
",html+='',html+=globalize.translate("sharedcomponents#LearnMore"),html+="
",html+=" 0&&progress<100&&(progress=progress.toFixed(1)),html+=progress+"%"}return html}function getSyncJobHtml(listInstance,job,apiClient){var html="",tagName=layoutManager.tv?"button":"div",typeAttribute="button"===tagName?' type="button"':"",listItemClass="listItem listItem-border";layoutManager.tv&&(listItemClass+=" listItem-button listItem-focusscale",listItemClass+=" btnJobMenu");var canEdit=(job.ItemCount||1)>1||"Queued"===job.Status;html+="<"+tagName+typeAttribute+' class="'+listItemClass+'" data-canedit="'+canEdit+'" data-id="'+job.Id+'" data-status="'+job.Status+'">';var imgUrl;job.PrimaryImageItemId&&(imgUrl=apiClient.getImageUrl(job.PrimaryImageItemId,{type:"Primary",width:80,tag:job.PrimaryImageTag,minScale:1.5})),imgUrl?(html+='',html+="
"):html+='file_download ';var textLines=[],name=job.Name;job.ParentName&&(name+=" - "+job.ParentName),textLines.push(name),1===job.ItemCount||textLines.push(globalize.translate("sharedcomponents#ItemCount",job.ItemCount)),html+='';for(var i=0,length=textLines.length;i
',html+=textLines[i],html+=""):(html+='',html+=textLines[i],html+="
");return html+='',html+=getProgressText(job),html+="
",html+=" ",layoutManager.tv||(html+=canEdit?'':'delete '),html+=""+tagName+">"}function renderList(listInstance,jobs,apiClient){if((new Date).getTime()-listInstance.lastDataLoad<6e4)return void refreshList(listInstance,jobs);listInstance.lastDataLoad=(new Date).getTime();for(var html="",lastTargetName="",mode=listInstance.options.mode,showTargetName="download"!==mode,hasOpenSection=!1,i=0,length=jobs.length;i",html+=" ",hasOpenSection=!1),lastTargetName=targetName,html+='',html+='
',html+='
'+targetName+" ",html+="",html+='
',hasOpenSection=!0)}html+=getSyncJobHtml(listInstance,job,apiClient)}hasOpenSection&&(html+="
",html+="
");var elem=listInstance.options.element.querySelector(".syncJobListContent");html||(html="download"===mode?''+globalize.translate("sharedcomponents#MessageNoDownloadsFound")+"
":''+globalize.translate("sharedcomponents#MessageNoSyncJobsFound")+"
"),elem.innerHTML=html,imageLoader.lazyChildren(elem)}function fetchData(listInstance){listInstance.lastDataLoad=0,loading.show();var options={},apiClient=getApiClient(listInstance);return listInstance.options.userId&&(options.UserId=listInstance.options.userId),"download"===listInstance.options.mode&&(options.TargetId=apiClient.deviceId()),apiClient.getJSON(apiClient.getUrl("Sync/Jobs",options)).then(function(response){renderList(listInstance,response.Items,apiClient),loading.hide()})}function getApiClient(listInstance){return connectionManager.getApiClient(listInstance.options.serverId)}function showJobMenu(listInstance,elem){var item=dom.parentWithClass(elem,"listItem"),jobId=item.getAttribute("data-id"),menuItems=(item.getAttribute("data-status"),[]);"true"===item.getAttribute("data-canedit")&&menuItems.push({name:globalize.translate("sharedcomponents#Edit"),id:"edit"});var txt=globalize.translate("sharedcomponents#RemoveDownload");menuItems.push({name:txt,id:"cancel"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:menuItems,positionTo:elem,callback:function(id){switch(id){case"delete":case"cancel":cancelJob(listInstance,jobId);break;case"edit":showJobEditor(listInstance,elem)}}})})}function onElementClick(e){var listInstance=this,btnJobMenu=dom.parentWithClass(e.target,"btnJobMenu");if(btnJobMenu)return void showJobMenu(listInstance,btnJobMenu);var btnCancelJob=dom.parentWithClass(e.target,"btnCancelJob");if(btnCancelJob){var listItem=dom.parentWithClass(btnCancelJob,"listItem");if(listItem){cancelJob(listInstance,listItem.getAttribute("data-id"))}}else showJobEditor(listInstance,e.target)}function showJobEditor(listInstance,elem){var listItem=dom.parentWithClass(elem,"listItem");if(listItem&&"true"===listItem.getAttribute("data-canedit")){var jobId=listItem.getAttribute("data-id");require(["syncJobEditor"],function(syncJobEditor){syncJobEditor.show({serverId:listInstance.options.serverId,jobId:jobId,mode:listInstance.options.mode}).then(function(){fetchData(listInstance)})})}}function syncJobList(options){this.options=options;var onSyncJobCreatedHandler=onSyncJobCreated.bind(this);this.onSyncJobCreatedHandler=onSyncJobCreatedHandler,events.on(serverNotifications,"SyncJobCreated",onSyncJobCreatedHandler);var onSyncJobCancelledHandler=onSyncJobCancelled.bind(this);this.onSyncJobCancelledHandler=onSyncJobCancelledHandler,events.on(serverNotifications,"SyncJobCancelled",onSyncJobCancelledHandler);var onSyncJobUpdatedHandler=onSyncJobUpdated.bind(this);this.onSyncJobUpdatedHandler=onSyncJobUpdatedHandler,events.on(serverNotifications,"SyncJobUpdated",onSyncJobUpdatedHandler);var onClickHandler=onElementClick.bind(this);options.element.addEventListener("click",onClickHandler),this.onClickHandler=onClickHandler,options.element.innerHTML='
',fetchData(this),initSupporterInfo(options.element,getApiClient(this))}function showSupporterInfo(context){var html='';html+="",html+=globalize.translate("sharedcomponents#HeaderSyncRequiresSub"),html+="
",html+='',html+=globalize.translate("sharedcomponents#LearnMore"),html+="
",html+=" option{color:inherit;background:#222}.emby-select-withcolor:focus{border-color:#52B54B!important}.emby-select-tv-withcolor:focus{background-color:#52B54B!important;color:#fff!important}.emby-checkbox:checked+span+span+.checkboxOutline{border-color:#52B54B}.emby-checkbox:focus+span+.emby-checkbox-focushelper{background-color:rgba(82,181,75,.26)}.emby-checkbox:checked+span+span+.checkboxOutline,.itemProgressBarForeground{background-color:#52B54B}.itemProgressBarForeground-recording{background-color:#CB272A}.countIndicator,.fullSyncIndicator,.playedIndicator{background:#52B54B}.fullSyncIndicator{color:#fff}.mainDrawer{background-color:#1c1c1c}.navMenuOption:hover{background:#252528}.navMenuOption-selected{background:#52B54B!important;color:#fff}.emby-button-focusscale:focus{background:#52B54B;color:#fff}.emby-tab-button{color:#999;color:rgba(255,255,255,.4)}.emby-tab-button-active{color:#52B54B}.emby-tab-button-active.emby-button-tv{color:#fff}.emby-tab-button.emby-button-tv:focus{color:#52B54B;background:0 0}.channelPrograms,.guide-channelHeaderCell,.programCell{border-color:rgba(255,255,255,.05)}.programCell-sports{background:#3949AB!important}.programCell-movie{background:#5E35B1!important}.programCell-kids{background:#039BE5!important}.programCell-news{background:#43A047!important}.programCell-active{background:#1e1e1e!important}.guide-channelHeaderCell:focus,.programCell:focus{background-color:#52B54B!important;color:#fff!important}.guide-programTextIcon{color:#1e1e1e;background:#555}.guide-headerTimeslots{color:inherit}.guide-date-tab-button{color:#555;color:rgba(255,255,255,.3)}.guide-date-tab-button.emby-tab-button-active,.guide-date-tab-button:focus{color:#52B54B}.guide-date-tab-button.emby-button-tv:focus{background-color:#52B54B;color:#fff}.itemBackdropFader{background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(#1a1a1a));background:-webkit-linear-gradient(rgba(0,0,0,0),#1a1a1a);background:-o-linear-gradient(rgba(0,0,0,0),#1a1a1a);background:linear-gradient(rgba(0,0,0,0),#1a1a1a)}.infoBanner{color:#ddd;background:#111;padding:1em;-webkit-border-radius:.25em;border-radius:.25em}.ratingbutton-icon-withrating{color:#c33}.downloadbutton-icon-complete,.downloadbutton-icon-on{color:#4285F4}.playstatebutton-icon-played{color:#c33}.repeatButton-active{color:#4285F4}.card:focus .card-focuscontent{border-color:#52B54B}.layout-desktop ::-webkit-scrollbar{width:1em;height:1em}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3)}::-webkit-scrollbar-track-piece{background-color:#3b3b3b}::-webkit-scrollbar-thumb:horizontal,::-webkit-scrollbar-thumb:vertical{-webkit-border-radius:2px;background:center no-repeat #888}.timeslotHeaders-desktop::-webkit-scrollbar{height:.7em}
\ No newline at end of file
+html{color:#ddd;color:rgba(255,255,255,.8)}.emby-collapsible-button{border-color:#383838;border-color:rgba(255,255,255,.135)}.skinHeader-withBackground{background-color:#1f1f1f}.skinHeader.semiTransparent{-webkit-backdrop-filter:none!important;backdrop-filter:none!important;background-color:rgba(0,0,0,.3);background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.6)),to(rgba(0,0,0,0)));background:-webkit-linear-gradient(rgba(0,0,0,.6),rgba(0,0,0,0));background:-o-linear-gradient(rgba(0,0,0,.6),rgba(0,0,0,0));background:linear-gradient(rgba(0,0,0,.6),rgba(0,0,0,0))}.pageTitleWithDefaultLogo{background-image:url(../logowhite.png)}.backgroundContainer,.dialog,html{background-color:#1a1a1a}.backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)}.paper-icon-button-light:focus{color:#52B54B;background-color:rgba(82,181,75,.2)}.fab,.raised{background:#303030;color:rgba(255,255,255,.87)}.fab:focus,.raised:focus{background:#383838}.button-submit{background:#52B54B;color:#fff}.button-submit:focus{background:#5EC157;color:#fff}.checkboxLabel{color:inherit}.checkboxListLabel,.inputLabel,.inputLabelUnfocused,.paperListLabel,.textareaLabelUnfocused{color:#bbb;color:rgba(255,255,255,.7)}.inputLabelFocused,.selectLabelFocused,.textareaLabelFocused{color:#52B54B}.checkboxOutline{border-color:currentColor}.collapseContent,.formDialogFooter:not(.formDialogFooter-clear),.formDialogHeader:not(.formDialogHeader-clear),.paperList,.visualCardBox{background-color:#242424}.defaultCardBackground1{background-color:#d2b019}.defaultCardBackground2{background-color:#338abb}.defaultCardBackground3{background-color:#6b689d}.defaultCardBackground4{background-color:#dd452b}.defaultCardBackground5{background-color:#5ccea9}.cardText-secondary,.fieldDescription,.guide-programNameCaret,.listItem .secondary,.nowPlayingBarSecondaryText,.programSecondaryTitle,.secondaryText{color:#999;color:rgba(255,255,255,.5)}.actionsheetDivider{background:#444;background:rgba(255,255,255,.14)}.cardFooter-vibrant .cardText-secondary{color:inherit;opacity:.5}.actionSheetMenuItem:hover{background-color:#242424}.toast{background:#303030;color:#fff;color:rgba(255,255,255,.87)}.appfooter{background:#101010;color:#ccc;color:rgba(255,255,255,.78)}@supports (backdrop-filter:blur(10px)) or (-webkit-backdrop-filter:blur(10px)){.appfooter-blurred{background:rgba(24,24,24,.7);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.itemSelectionPanel{border:1px solid #52B54B}.selectionCommandsPanel{background:#52B54B;color:#fff}.upNextDialog-countdownText{color:#52B54B}.alphaPickerButton{color:#999;color:rgba(255,255,255,.5);background-color:transparent}.alphaPickerButton-selected{color:#fff}.alphaPickerButton-tv:focus{background-color:#52B54B;color:#fff!important}.detailTableBodyRow-shaded:nth-child(even){background:#1c1c1c;background:rgba(30,30,30,.9)}.listItem-border{border-color:rgba(46,46,46,.9)!important}.listItem:focus{background:#333}.progressring-spiner{border-color:#52B54B}.button-flat-accent,.button-link{color:#52B54B}.mediaInfoText{color:#ddd;background:rgba(170,170,190,.2)}.mediaInfoTimerIcon,.starIcon{color:#CB272A}.emby-input,.emby-textarea{color:inherit;background:#292929;border:.07em solid #292929;-webkit-border-radius:.15em;border-radius:.15em}.emby-input:focus,.emby-textarea:focus{border-color:#52B54B}.emby-select-withcolor{color:inherit;background:#292929;border:.07em solid #292929}.emby-select-withcolor>option{color:inherit;background:#222}.emby-select-withcolor:focus{border-color:#52B54B!important}.emby-select-tv-withcolor:focus{background-color:#52B54B!important;color:#fff!important}.emby-checkbox:checked+span+span+.checkboxOutline{border-color:#52B54B}.emby-checkbox:focus+span+.emby-checkbox-focushelper{background-color:rgba(82,181,75,.26)}.emby-checkbox:checked+span+span+.checkboxOutline,.itemProgressBarForeground{background-color:#52B54B}.itemProgressBarForeground-recording{background-color:#CB272A}.countIndicator,.fullSyncIndicator,.playedIndicator{background:#52B54B}.fullSyncIndicator{color:#fff}.mainDrawer{background-color:#1c1c1c}.navMenuOption:hover{background:#252528}.navMenuOption-selected{background:#52B54B!important;color:#fff}.emby-button-focusscale:focus{background:#52B54B;color:#fff}.emby-tab-button{color:#999;color:rgba(255,255,255,.4)}.emby-tab-button-active{color:#52B54B}.emby-tab-button-active.emby-button-tv{color:#fff}.emby-tab-button.emby-button-tv:focus{color:#52B54B;background:0 0}.channelPrograms,.guide-channelHeaderCell,.programCell{border-color:rgba(255,255,255,.05)}.programCell-sports{background:#3949AB!important}.programCell-movie{background:#5E35B1!important}.programCell-kids{background:#039BE5!important}.programCell-news{background:#43A047!important}.programCell-active{background:#1e1e1e!important}.guide-channelHeaderCell:focus,.programCell:focus{background-color:#52B54B!important;color:#fff!important}.guide-programTextIcon{color:#1e1e1e;background:#555}.guide-headerTimeslots{color:inherit}.guide-date-tab-button{color:#555;color:rgba(255,255,255,.3)}.guide-date-tab-button.emby-tab-button-active,.guide-date-tab-button:focus{color:#52B54B}.guide-date-tab-button.emby-button-tv:focus{background-color:#52B54B;color:#fff}.itemBackdropFader{background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(#1a1a1a));background:-webkit-linear-gradient(rgba(0,0,0,0),#1a1a1a);background:-o-linear-gradient(rgba(0,0,0,0),#1a1a1a);background:linear-gradient(rgba(0,0,0,0),#1a1a1a)}.infoBanner{color:#ddd;background:#111;padding:1em;-webkit-border-radius:.25em;border-radius:.25em}.ratingbutton-icon-withrating{color:#c33}.downloadbutton-icon-complete,.downloadbutton-icon-on{color:#4285F4}.playstatebutton-icon-played{color:#c33}.repeatButton-active{color:#4285F4}.card:focus .card-focuscontent{border-color:#52B54B}.layout-desktop ::-webkit-scrollbar{width:1em;height:1em}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3)}::-webkit-scrollbar-track-piece{background-color:#3b3b3b}::-webkit-scrollbar-thumb:horizontal,::-webkit-scrollbar-thumb:vertical{-webkit-border-radius:2px;background:center no-repeat #888}.timeslotHeaders-desktop::-webkit-scrollbar{height:.7em}
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/components/filterdialog/filterdialog.js b/MediaBrowser.WebDashboard/dashboard-ui/components/filterdialog/filterdialog.js
index 0e1c9f8a0c..17d79f670f 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/components/filterdialog/filterdialog.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/components/filterdialog/filterdialog.js
@@ -1 +1 @@
-define(["dialogHelper","globalize","connectionManager","events","browser","require","emby-checkbox","emby-collapse","css!./style"],function(dialogHelper,globalize,connectionManager,events,browser,require){"use strict";function renderOptions(context,selector,cssClass,items,isCheckedFn){var elem=context.querySelector(selector);items.length?elem.classList.remove("hide"):elem.classList.add("hide");var html="";html+='',html+=items.map(function(filter){var itemHtml="",checkedHtml=isCheckedFn(filter)?" checked":"";return itemHtml+="",itemHtml+=' ',itemHtml+=""+filter+" ",itemHtml+=" "}).join(""),html+="
",elem.querySelector(".filterOptions").innerHTML=html}function renderFilters(context,result,query){result.Tags&&(result.Tags.length=Math.min(result.Tags.length,50)),renderOptions(context,".genreFilters","chkGenreFilter",result.Genres,function(i){return-1!=("|"+(query.Genres||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".officialRatingFilters","chkOfficialRatingFilter",result.OfficialRatings,function(i){return-1!=("|"+(query.OfficialRatings||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".tagFilters","chkTagFilter",result.Tags,function(i){return-1!=("|"+(query.Tags||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".yearFilters","chkYearFilter",result.Years,function(i){return-1!=(","+(query.Years||"")+",").indexOf(","+i+",")})}function loadDynamicFilters(context,apiClient,userId,itemQuery){return apiClient.getJSON(apiClient.getUrl("Items/Filters",{UserId:userId,ParentId:itemQuery.ParentId,IncludeItemTypes:itemQuery.IncludeItemTypes})).then(function(result){renderFilters(context,result,itemQuery)})}function updateFilterControls(context,options){var elems,i,length,query=options.query;if("livetvchannels"==options.mode)context.querySelector(".chkFavorite").checked=1==query.IsFavorite,context.querySelector(".chkLikes").checked=1==query.IsLiked,context.querySelector(".chkDislikes").checked=1==query.IsDisliked;else for(elems=context.querySelectorAll(".chkStandardFilter"),i=0,length=elems.length;i',html+=items.map(function(filter){var itemHtml="",checkedHtml=isCheckedFn(filter)?" checked":"";return itemHtml+="",itemHtml+=' ',itemHtml+=""+filter+" ",itemHtml+=" "}).join(""),html+="",elem.querySelector(".filterOptions").innerHTML=html}function renderFilters(context,result,query){result.Tags&&(result.Tags.length=Math.min(result.Tags.length,50)),renderOptions(context,".genreFilters","chkGenreFilter",result.Genres,function(i){return-1!=("|"+(query.Genres||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".officialRatingFilters","chkOfficialRatingFilter",result.OfficialRatings,function(i){return-1!=("|"+(query.OfficialRatings||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".tagFilters","chkTagFilter",result.Tags,function(i){return-1!=("|"+(query.Tags||"")+"|").indexOf("|"+i+"|")}),renderOptions(context,".yearFilters","chkYearFilter",result.Years,function(i){return-1!=(","+(query.Years||"")+",").indexOf(","+i+",")})}function loadDynamicFilters(context,apiClient,userId,itemQuery){return apiClient.getJSON(apiClient.getUrl("Items/Filters",{UserId:userId,ParentId:itemQuery.ParentId,IncludeItemTypes:itemQuery.IncludeItemTypes})).then(function(result){renderFilters(context,result,itemQuery)})}function updateFilterControls(context,options){var elems,i,length,query=options.query;if("livetvchannels"==options.mode)context.querySelector(".chkFavorite").checked=1==query.IsFavorite,context.querySelector(".chkLikes").checked=1==query.IsLiked,context.querySelector(".chkDislikes").checked=1==query.IsDisliked;else for(elems=context.querySelectorAll(".chkStandardFilter"),i=0,length=elems.length;i
${OptionIsHD}
+
+
+ 4K
+
+
${OptionIsSD}
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css b/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css
index e904b7d518..e9a69632da 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css
+++ b/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css
@@ -1 +1 @@
-.headerUserImage,.navMenuOption,.pageTitle{vertical-align:middle}.detailButton-mobile,.itemLinks,.listPaging,.sectionTabs,.viewSettings{text-align:center}.headerSelectedPlayer,.itemMiscInfo{-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden}.libraryPage{padding-top:7em!important}.itemDetailPage{padding-top:4em!important}.standalonePage{padding-top:4.5em!important}.wizardPage{padding-top:7em!important}.libraryPage:not(.noSecondaryNavPage){padding-top:7.5em!important}.absolutePageTabContent{position:absolute;left:0;right:0;bottom:0;z-index:1;margin:0!important;top:6.9em!important;-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.pageTabContent:not(.is-active){display:none!important}.headerUserImage{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center center;-webkit-border-radius:100em;border-radius:100em;display:inline-block}.headerUserButtonRound img{-webkit-border-radius:100em;border-radius:100em}.headerButton{-webkit-flex-shrink:0;flex-shrink:0}.hideMainDrawer .mainDrawerButton{display:none}.noHeaderRight .headerRight,.noHomeButtonHeader .headerHomeButton{display:none!important}.pageTitle{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;margin:0 0 0 .5em;height:1.7em;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-flex-shrink:1;flex-shrink:1}.headerLeft,.skinHeader{display:-webkit-box;display:-webkit-flex}.detailButton-mobile,.skinHeader{-webkit-flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal}.pageTitleWithLogo{background-position:left center;-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;width:13.2em}.pageTitleWithDefaultLogo{height:1.22em}.skinHeader{position:fixed;right:0;left:0;z-index:999;top:0;border:0;display:flex;flex-direction:column;contain:layout style paint}.headerLeft,.headerRight{-webkit-box-align:center}.mainAnimatedPages,.pageTabContent{contain:layout style}.hiddenViewMenuBar .skinHeader{display:none}.headerTop{padding:.865em 0}.headerLeft{display:flex;-webkit-align-items:center;align-items:center;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;overflow:hidden}.sectionTabs{width:100%}.headerRight{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.selectedMediaFolder{background-color:#f2f2f2!important}.navMenuOption{display:-webkit-box!important;display:-webkit-flex!important;display:flex!important;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-decoration:none;color:inherit;padding:.9em 0 .9em 2.4em!important;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;font-weight:400!important;margin:0!important;-webkit-border-radius:0!important;border-radius:0!important}.layout-desktop .searchTabButton,.layout-mobile .searchTabButton,.layout-tv .headerSearchButton,body:not(.dashboardDocument) .btnNotifications{display:none!important}.navMenuOptionIcon{margin-right:1em;-webkit-flex-shrink:0;flex-shrink:0}.sidebarHeader{padding-left:1.2em;margin:1em 0 .5em}.dashboardDocument .skinBody{-webkit-transition:left ease-in-out .3s,padding ease-in-out .3s;-o-transition:left ease-in-out .3s,padding ease-in-out .3s;transition:left ease-in-out .3s,padding ease-in-out .3s;position:absolute;top:0;right:0;bottom:0;left:0}.mainDrawer-scrollContainer{padding-bottom:10vh}@media all and (min-width:40em){.dashboardDocument .adminDrawerLogo,.dashboardDocument .mainDrawerButton{display:none!important}.dashboardDocument .mainDrawer{z-index:inherit!important;left:0!important;top:0!important;-webkit-transform:none!important;transform:none!important;-webkit-box-shadow:none!important;box-shadow:none!important;width:20.205em!important;font-size:94%}.dashboardDocument .mainDrawer-scrollContainer{margin-top:5em!important}.dashboardDocument withSectionTabs .mainDrawer-scrollContainer{margin-top:8.7em!important}.dashboardDocument .skinBody{left:20em}}@media all and (min-width:40em) and (max-width:84em){.dashboardDocument.withSectionTabs .mainDrawer-scrollContainer{margin-top:8.4em!important}}@media all and (max-width:60em){.libraryDocument .mainDrawerButton{display:none}}@media all and (max-width:84em){.withSectionTabs .headerTop{padding-bottom:.2em}.sectionTabs{font-size:83.5%}}@media all and (min-width:84em){.headerTop{padding:1.489em 0}.headerTabs{-webkit-align-self:center;align-self:center;width:auto;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;margin-top:-3.34em;position:relative;top:-1.05em}.libraryPage:not(.noSecondaryNavPage){padding-top:4.6em!important}.pageWithAbsoluteTabs:not(.noSecondaryNavPage){padding-top:6.7em!important}.absolutePageTabContent{top:5.7em!important}.dashboardDocument.withSectionTabs .mainDrawer-scrollContainer{margin-top:6.1em!important}.dashboardDocument .mainDrawer-scrollContainer{margin-top:6.3em!important}}.headerSelectedPlayer{max-width:10em;white-space:nowrap}@media all and (max-width:37.5em){.headerSelectedPlayer{display:none}}.hidingAnimatedTab{visibility:hidden}.headerArrowImage{height:20px;margin-left:.5em}.backdropContainer{position:fixed;top:0;left:0;right:0;bottom:0;z-index:-1}.libraryPage .header{padding-bottom:0}.flexPageTabContent.is-active{display:-webkit-box!important;display:-webkit-flex!important;display:flex!important}.viewSettings{margin:0 0 .25em}.viewControls+.listTopPaging{margin-left:.5em!important}.criticReview{margin:1.5em 0;background:#222;padding:.8em .8em .8em 3em;-webkit-border-radius:.3em;border-radius:.3em;position:relative}.detailLogo,.itemBackdrop{background-repeat:no-repeat;background-position:center center}.criticReview:first-child{margin-top:.5em}.criticReview img{width:2.4em}.criticRatingScore{margin-bottom:.5em}.itemTag{display:inline-block;margin-right:1em}.itemOverview{white-space:pre-wrap}.itemLinks{padding:0}.itemLinks p{margin:.5em 0}.reviewLink,.reviewerName{margin-top:.5em}.reviewerName{color:#ccc}.reviewDate{margin-left:1em}.reviewScore{position:absolute;left:.8em}.itemBackdrop{-webkit-background-size:cover;background-size:cover;height:50vh;position:relative}.itemBackdropProgressBar{position:absolute!important;bottom:0;left:0;right:0}.itemBackdropFader{position:absolute;bottom:-1px;left:0;right:0;height:15vh}.desktopMiscInfoContainer{position:absolute;bottom:.75em}.detailImageContainer{margin-right:2em;width:280px;-webkit-flex-shrink:0;flex-shrink:0}.detailPagePrimaryContent{position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.detailLogo{width:21.3em;height:5em;position:absolute;top:13.5%;right:19.5%;-webkit-background-size:contain;background-size:contain}@media all and (max-width:87.5em){.detailLogo{right:5%}}@media all and (max-width:75em){.detailLogo{right:2%}}@media all and (max-width:68.75em){.detailLogo{width:14.91em;height:3.5em;right:5%;bottom:5%;top:auto;background-position:center right;display:none}}.itemDetailImage{width:100%}.thumbDetailImageContainer{width:400px}.itemDetailImage.loaded{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37)}@media all and (max-width:62.5em){.detailPageContent{position:relative}.detailImageContainer{position:absolute;top:-90px;left:5%;width:auto}.itemDetailImage{height:120px;width:auto!important}.btnPlaySimple{display:none!important}}@media all and (min-width:62.5em){.itemBackdrop{display:none}.detailPagePrimaryContainer{display:-webkit-box;display:-webkit-flex;display:flex;margin-bottom:3.6em}}@media all and (max-width:75em){.lnkSibling{display:none!important}}.parentName{display:block;margin-bottom:.5em}.emby-button.detailFloatingButton{position:absolute;background-color:rgba(0,0,0,.5)!important;z-index:1;top:50%;left:50%;margin:-2.2em 0 0 -2.2em;border:2.7px solid rgba(255,255,255,.6);padding:.38em!important;color:rgba(255,255,255,.76)}.emby-button.detailFloatingButton i{font-size:3.5em}@media all and (max-width:62.5em){.parentName{margin-bottom:1em}.itemDetailPage{padding-top:0!important}.detailimg-hidemobile{display:none}}@media all and (min-width:31.25em){.mobileDetails{display:none}}@media all and (max-width:31.25em){.desktopDetails{display:none!important}}.detailButton-mobile,.mainDetailButtons{display:-webkit-box;display:-webkit-flex}.itemName{margin:.5em 0}.empty{margin:0}.detailCollapsibleSection:not(.hide)+.detailCollapsibleSection{margin-top:-2em}.detailPageCollabsible{margin-top:0}.mainDetailButtons{display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-flex-wrap:wrap;flex-wrap:wrap;margin:1em 0}.recordingFields button{margin-left:0;margin-right:.5em;-webkit-flex-shrink:0;flex-shrink:0}.mainDetailButtons.hide+.recordingFields{margin-top:1.5em!important}.detailButton-mobile{display:flex;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin:0!important;padding:.5em .7em!important}.detailButton{margin:0 .5em 0 0!important}@media all and (min-width:29em){.detailButton-mobile{padding-left:.75em!important;padding-right:.75em!important}}@media all and (min-width:32em){.detailButton-mobile{padding-left:.8em!important;padding-right:.8em!important}}@media all and (min-width:35em){.detailButton-mobile{padding-left:.85em!important;padding-right:.85em!important}}.detailButton-mobile-content{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.detailButton-mobile-icon{font-size:1.6em!important;width:1em;height:1em}.detailImageProgressContainer{position:absolute;bottom:4px;right:1px;left:1px;text-align:center}.detailButton-mobile-text{margin-top:.7em;font-size:80%;font-weight:400}@media all and (max-width:62.5em){.mainDetailButtons{margin-left:-.5em}.detailButton{display:none!important}}@media all and (min-width:62.5em){.detailButton-mobile{display:none!important}.mainDetailButtons{font-size:108%;margin:1.25em 0}}.listTopPaging,.viewControls{display:inline-block}@media all and (max-width:50em){.editorMenuLink{display:none}}.itemMiscInfo{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-webkit-align-items:center;align-items:center}@media all and (max-width:31.25em){.mobileDetails .itemMiscInfo{text-align:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.itemMiscInfo .endsAt{display:none}}.layout-tv .detailVerticalSection{margin-bottom:3.4em!important}.detailPageContent{border-spacing:0;border-collapse:collapse;padding-top:3em}@media all and (max-width:62.5em){.detailPageContent-nodetailimg{padding-top:0;margin-top:-3em}}@media all and (min-width:75em){.itemDetailPage .padded-left{padding-left:4%!important}.itemDetailPage .padded-right{padding-right:4%!important}}.mediaInfoStream{margin:0 3em 0 0;display:inline-block;vertical-align:top}.mediaInfoStreamType{display:block;margin:1em 0}.mediaInfoAttribute,.mediaInfoLabel{display:inline-block}.mediaInfoLabel{margin-right:1em;font-weight:600}.recordingProgressBar::-moz-progress-bar{background-color:#c33}.recordingProgressBar::-webkit-progress-value{background-color:#c33}.recordingProgressBar[aria-valuenow]:before{background-color:#c33}.timelineHeader{margin-bottom:.25em;line-height:1.25em;line-height:initial}.itemsContainer{margin:0 auto}@media all and (max-height:31.25em){.itemBackdrop{height:52vh}}@media all and (max-width:75em){.listViewUserDataButtons{display:none!important}}@media all and (max-width:62.5em){.detailsHiddenOnMobile{display:none}}.btnSyncComplete{background:#673AB7!important}.btnSyncComplete i{-webkit-border-radius:1000px;border-radius:1000px}.bulletSeparator{margin:0 .35em}.mediaInfoIcons{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin:1em 0;-webkit-flex-wrap:wrap;flex-wrap:wrap}.verticalSection-extrabottompadding{margin-bottom:2.7em}.sectionTitleContainer{margin:1.25em 0}.sectionTitleButton,.sectionTitleIconButton{margin-right:0!important;display:inline-block;vertical-align:middle}.sectionTitleContainer-cards{margin-bottom:.1em}.sectionTitle{margin-bottom:1em}.sectionTitle-cards{margin-left:.55em;margin-bottom:0}@media all and (max-width:50em){.sectionTitle-cards{margin-left:.28em}}.sectionTitleContainer>.sectionTitle{margin-top:0;margin-bottom:0;display:inline-block;vertical-align:middle}.sectionTitleButton{margin-left:1.5em!important;-webkit-flex-shrink:0;flex-shrink:0}.sectionTitleButton+.sectionTitleButton{margin-left:.5em!important}.sectionTitleIconButton{margin-left:1.5em!important;-webkit-flex-shrink:0;flex-shrink:0;font-size:84%!important;padding:.5em!important}.horizontalItemsContainer{display:-webkit-box;display:-webkit-flex;display:flex}.sectionTitleTextButton{margin:0!important;display:-webkit-inline-box!important;display:-webkit-inline-flex!important;display:inline-flex!important;color:inherit!important}.sectionTitleTextButton:not(.padded-left){padding:0!important}.sectionTitleTextButton.padded-left{padding-bottom:0!important;padding-right:0!important;padding-top:0!important}.sectionTitleTextButton>.sectionTitle{margin-bottom:0;margin-top:0}.padded-left{padding-left:2%}.padded-right{padding-right:2%}.padded-top{padding-top:1em}.padded-bottom{padding-bottom:1em}.layout-tv .padded-top-focusscale{padding-top:1.6em;margin-top:-1.6em}.layout-tv .padded-bottom-focusscale{padding-bottom:1.6em;margin-bottom:-1.6em}@media all and (min-height:500px){.padded-left-withalphapicker{padding-left:7.5%}.padded-right-withalphapicker{padding-right:7.5%}}@media all and (min-width:500px){.padded-left{padding-left:6%}.padded-right{padding-right:6%}}@media all and (min-width:600px){.padded-left{padding-left:4%}.padded-right{padding-right:4%}}@media all and (min-width:800px){.padded-left{padding-left:3.2%}.padded-right{padding-right:3.2%}}@media all and (min-width:1280px){.padded-left{padding-left:3.3%}.padded-right{padding-right:3.3%}}@media all and (min-width:800px){.layout-tv .padded-left-withalphapicker{padding-left:4.5%}.layout-tv .padded-right-withalphapicker{padding-right:4.5%}}.searchfields-icon{color:#aaa}.button-accent-flat{color:#52B54B!important}.clearLink{text-decoration:none;font-weight:inherit!important;vertical-align:middle;color:inherit!important}.itemsViewSettingsContainer{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}@media all and (min-width:40em){.listIconButton-autohide{display:none!important}}@media all and (max-width:40em){.listTextButton-autohide{display:none!important}}.layout-tv .itemsViewSettingsContainer{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;padding:1.5em .75em 1em 0;font-size:92%}.itemsViewSettingsContainer>.button-flat{margin:0}
\ No newline at end of file
+.headerUserImage,.navMenuOption,.pageTitle{vertical-align:middle}.detailButton-mobile,.itemLinks,.listPaging,.sectionTabs,.viewSettings{text-align:center}.headerSelectedPlayer,.itemMiscInfo{-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden}.libraryPage{padding-top:7em!important}.itemDetailPage{padding-top:4em!important}.standalonePage{padding-top:4.5em!important}.wizardPage{padding-top:7em!important}.libraryPage:not(.noSecondaryNavPage){padding-top:7.5em!important}.absolutePageTabContent{position:absolute;left:0;right:0;bottom:0;z-index:1;margin:0!important;top:6.9em!important;-webkit-transition:-webkit-transform .2s ease-out;-o-transition:transform .2s ease-out;transition:transform .2s ease-out}.pageTabContent:not(.is-active){display:none!important}.headerUserImage{-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:center center;-webkit-border-radius:100em;border-radius:100em;display:inline-block}.headerUserButtonRound img{-webkit-border-radius:100em;border-radius:100em}.headerButton{-webkit-flex-shrink:0;flex-shrink:0}.hideMainDrawer .mainDrawerButton{display:none}.noHeaderRight .headerRight,.noHomeButtonHeader .headerHomeButton{display:none!important}.pageTitle{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;margin:0 0 0 .5em;height:1.7em;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-flex-shrink:1;flex-shrink:1}.headerLeft,.skinHeader{display:-webkit-box;display:-webkit-flex}.detailButton-mobile,.skinHeader{-webkit-flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal}.pageTitleWithLogo{background-position:left center;-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;width:13.2em}.pageTitleWithDefaultLogo{height:1.22em}.skinHeader{position:fixed;right:0;left:0;z-index:999;top:0;border:0;display:flex;flex-direction:column;contain:layout style paint}.headerLeft,.headerRight{-webkit-box-align:center}.mainAnimatedPages,.pageTabContent{contain:layout style}.hiddenViewMenuBar .skinHeader{display:none}.headerTop{padding:.865em 0}.headerLeft{display:flex;-webkit-align-items:center;align-items:center;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;overflow:hidden}.sectionTabs{width:100%}.headerRight{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.selectedMediaFolder{background-color:#f2f2f2!important}.navMenuOption{display:-webkit-box!important;display:-webkit-flex!important;display:flex!important;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-decoration:none;color:inherit;padding:.9em 0 .9em 2.4em!important;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;font-weight:400!important;margin:0!important;-webkit-border-radius:0!important;border-radius:0!important}.layout-desktop .searchTabButton,.layout-mobile .searchTabButton,.layout-tv .headerSearchButton,body:not(.dashboardDocument) .btnNotifications{display:none!important}.navMenuOptionIcon{margin-right:1em;-webkit-flex-shrink:0;flex-shrink:0}.sidebarHeader{padding-left:1.2em;margin:1em 0 .5em}.dashboardDocument .skinBody{-webkit-transition:left ease-in-out .3s,padding ease-in-out .3s;-o-transition:left ease-in-out .3s,padding ease-in-out .3s;transition:left ease-in-out .3s,padding ease-in-out .3s;position:absolute;top:0;right:0;bottom:0;left:0}.mainDrawer-scrollContainer{padding-bottom:10vh}@media all and (min-width:40em){.dashboardDocument .adminDrawerLogo,.dashboardDocument .mainDrawerButton{display:none!important}.dashboardDocument .mainDrawer{z-index:inherit!important;left:0!important;top:0!important;-webkit-transform:none!important;transform:none!important;-webkit-box-shadow:none!important;box-shadow:none!important;width:20.205em!important;font-size:94%}.dashboardDocument .mainDrawer-scrollContainer{margin-top:5em!important}.dashboardDocument withSectionTabs .mainDrawer-scrollContainer{margin-top:8.7em!important}.dashboardDocument .skinBody{left:20em}}@media all and (min-width:40em) and (max-width:84em){.dashboardDocument.withSectionTabs .mainDrawer-scrollContainer{margin-top:8.4em!important}}@media all and (max-width:60em){.libraryDocument .mainDrawerButton{display:none}}@media all and (max-width:84em){.withSectionTabs .headerTop{padding-bottom:.2em}.sectionTabs{font-size:83.5%}}@media all and (min-width:84em){.headerTop{padding:1.489em 0}.headerTabs{-webkit-align-self:center;align-self:center;width:auto;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;margin-top:-3.34em;position:relative;top:-1.05em}.libraryPage:not(.noSecondaryNavPage){padding-top:4.6em!important}.pageWithAbsoluteTabs:not(.noSecondaryNavPage){padding-top:6.7em!important}.absolutePageTabContent{top:5.7em!important}.dashboardDocument.withSectionTabs .mainDrawer-scrollContainer{margin-top:6.1em!important}.dashboardDocument .mainDrawer-scrollContainer{margin-top:6.3em!important}}.headerSelectedPlayer{max-width:10em;white-space:nowrap}@media all and (max-width:37.5em){.headerSelectedPlayer{display:none}}.hidingAnimatedTab{visibility:hidden}.headerArrowImage{height:20px;margin-left:.5em}.backdropContainer{position:fixed;top:0;left:0;right:0;bottom:0;z-index:-1}.libraryPage .header{padding-bottom:0}.flexPageTabContent.is-active{display:-webkit-box!important;display:-webkit-flex!important;display:flex!important}.viewSettings{margin:0 0 .25em}.viewControls+.listTopPaging{margin-left:.5em!important}.criticReview{margin:1.5em 0;background:#222;padding:.8em .8em .8em 3em;-webkit-border-radius:.3em;border-radius:.3em;position:relative}.detailLogo,.itemBackdrop{background-repeat:no-repeat;background-position:center center}.criticReview:first-child{margin-top:.5em}.criticReview img{width:2.4em}.criticRatingScore{margin-bottom:.5em}.itemTag{display:inline-block;margin-right:1em}.itemOverview{white-space:pre-wrap}.itemLinks{padding:0}.itemLinks p{margin:.5em 0}.reviewLink,.reviewerName{margin-top:.5em}.reviewerName{color:#ccc}.reviewDate{margin-left:1em}.reviewScore{position:absolute;left:.8em}.itemBackdrop{-webkit-background-size:cover;background-size:cover;height:50vh;position:relative}.itemBackdropProgressBar{position:absolute!important;bottom:0;left:0;right:0}.itemBackdropFader{position:absolute;bottom:-1px;left:0;right:0;height:15vh}.desktopMiscInfoContainer{position:absolute;bottom:.75em}.detailImageContainer{margin-right:2em;width:280px;-webkit-flex-shrink:0;flex-shrink:0}.detailPagePrimaryContent{position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.detailLogo{width:21.3em;height:5em;position:absolute;top:13.5%;right:19.5%;-webkit-background-size:contain;background-size:contain}@media all and (max-width:87.5em){.detailLogo{right:5%}}@media all and (max-width:75em){.detailLogo{right:2%}}@media all and (max-width:68.75em){.detailLogo{width:14.91em;height:3.5em;right:5%;bottom:5%;top:auto;background-position:center right;display:none}}.itemDetailImage{width:100%}.thumbDetailImageContainer{width:400px}.itemDetailImage.loaded{-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37)}@media all and (max-width:62.5em){.detailPageContent{position:relative}.detailImageContainer{position:absolute;top:-90px;left:5%;width:auto}.itemDetailImage{height:120px;width:auto!important}.btnPlaySimple{display:none!important}}@media all and (min-width:62.5em){.itemBackdrop{display:none}.detailPagePrimaryContainer{display:-webkit-box;display:-webkit-flex;display:flex;margin-bottom:3.6em}}@media all and (max-width:75em){.lnkSibling{display:none!important}}.parentName{display:block;margin-bottom:.5em}.emby-button.detailFloatingButton{position:absolute;background-color:rgba(0,0,0,.5)!important;z-index:1;top:50%;left:50%;margin:-2.2em 0 0 -2.2em;border:2.7px solid rgba(255,255,255,.6);padding:.38em!important;color:rgba(255,255,255,.76)}.emby-button.detailFloatingButton i{font-size:3.5em}@media all and (max-width:62.5em){.parentName{margin-bottom:1em}.itemDetailPage{padding-top:0!important}.detailimg-hidemobile{display:none}}@media all and (min-width:31.25em){.mobileDetails{display:none}}@media all and (max-width:31.25em){.desktopDetails{display:none!important}}.detailButton-mobile,.mainDetailButtons{display:-webkit-box;display:-webkit-flex}.itemName{margin:.5em 0}.empty{margin:0}.detailCollapsibleSection:not(.hide)+.detailCollapsibleSection{margin-top:-2em}.detailPageCollabsible{margin-top:0}.mainDetailButtons{display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-flex-wrap:wrap;flex-wrap:wrap;margin:1em 0}.recordingFields button{margin-left:0;margin-right:.5em;-webkit-flex-shrink:0;flex-shrink:0}.mainDetailButtons.hide+.recordingFields{margin-top:1.5em!important}.detailButton-mobile{display:flex;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin:0!important;padding:.5em .7em!important}.detailButton{margin:0 .5em 0 0!important}@media all and (min-width:29em){.detailButton-mobile{padding-left:.75em!important;padding-right:.75em!important}}@media all and (min-width:32em){.detailButton-mobile{padding-left:.8em!important;padding-right:.8em!important}}@media all and (min-width:35em){.detailButton-mobile{padding-left:.85em!important;padding-right:.85em!important}}.detailButton-mobile-content{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.detailButton-mobile-icon{font-size:1.6em!important;width:1em;height:1em}.detailImageProgressContainer{position:absolute;bottom:4px;right:1px;left:1px;text-align:center}.detailButton-mobile-text{margin-top:.7em;font-size:80%;font-weight:400}@media all and (max-width:62.5em){.mainDetailButtons{margin-left:-.5em}.detailButton{display:none!important}}@media all and (min-width:62.5em){.detailButton-mobile{display:none!important}.mainDetailButtons{font-size:108%;margin:1.25em 0}}.listTopPaging,.viewControls{display:inline-block}@media all and (max-width:50em){.editorMenuLink{display:none}}.itemMiscInfo{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-webkit-align-items:center;align-items:center}@media all and (max-width:31.25em){.mobileDetails .itemMiscInfo{text-align:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.itemMiscInfo .endsAt{display:none}}.layout-tv .detailVerticalSection{margin-bottom:3.4em!important}.detailPageContent{border-spacing:0;border-collapse:collapse;padding-top:3em}@media all and (max-width:62.5em){.detailPageContent-nodetailimg{padding-top:0;margin-top:-3em}}@media all and (min-width:75em){.itemDetailPage .padded-left{padding-left:4%!important}.itemDetailPage .padded-right{padding-right:4%!important}}.mediaInfoStream{margin:0 3em 0 0;display:inline-block;vertical-align:top}.mediaInfoStreamType{display:block;margin:1em 0}.mediaInfoAttribute,.mediaInfoLabel{display:inline-block}.mediaInfoLabel{margin-right:1em;font-weight:600}.recordingProgressBar::-moz-progress-bar{background-color:#c33}.recordingProgressBar::-webkit-progress-value{background-color:#c33}.recordingProgressBar[aria-valuenow]:before{background-color:#c33}.timelineHeader{margin-bottom:.25em;line-height:1.25em;line-height:initial}.itemsContainer{margin:0 auto}@media all and (max-height:31.25em){.itemBackdrop{height:52vh}}@media all and (max-width:75em){.listViewUserDataButtons{display:none!important}}@media all and (max-width:62.5em){.detailsHiddenOnMobile{display:none}}.btnSyncComplete{background:#673AB7!important}.btnSyncComplete i{-webkit-border-radius:100em;border-radius:100em}.bulletSeparator{margin:0 .35em}.mediaInfoIcons{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin:1em 0;-webkit-flex-wrap:wrap;flex-wrap:wrap}.verticalSection-extrabottompadding{margin-bottom:2.7em}.sectionTitleContainer{margin:1.25em 0}.sectionTitleButton,.sectionTitleIconButton{margin-right:0!important;display:inline-block;vertical-align:middle}.sectionTitleContainer-cards{margin-bottom:.1em}.sectionTitle{margin-bottom:1em}.sectionTitle-cards{margin-left:.28em;margin-bottom:0}@media all and (min-width:50em){.sectionTitle-cards{margin-left:.6em}}.sectionTitleContainer>.sectionTitle{margin-top:0;margin-bottom:0;display:inline-block;vertical-align:middle}.sectionTitleButton{margin-left:1.5em!important;-webkit-flex-shrink:0;flex-shrink:0}.sectionTitleButton+.sectionTitleButton{margin-left:.5em!important}.sectionTitleIconButton{margin-left:1.5em!important;-webkit-flex-shrink:0;flex-shrink:0;font-size:84%!important;padding:.5em!important}.horizontalItemsContainer{display:-webkit-box;display:-webkit-flex;display:flex}.sectionTitleTextButton{margin:0!important;display:-webkit-inline-box!important;display:-webkit-inline-flex!important;display:inline-flex!important;color:inherit!important}.sectionTitleTextButton:not(.padded-left){padding:0!important}.sectionTitleTextButton.padded-left{padding-bottom:0!important;padding-right:0!important;padding-top:0!important}.sectionTitleTextButton>.sectionTitle{margin-bottom:0;margin-top:0}.padded-left{padding-left:2%}.padded-right{padding-right:2%}.padded-top{padding-top:1em}.padded-bottom{padding-bottom:1em}.layout-tv .padded-top-focusscale{padding-top:1.6em;margin-top:-1.6em}.layout-tv .padded-bottom-focusscale{padding-bottom:1.6em;margin-bottom:-1.6em}@media all and (min-height:31.25em){.padded-left-withalphapicker{padding-left:7.5%}.padded-right-withalphapicker{padding-right:7.5%}}@media all and (min-width:31.25em){.padded-left{padding-left:6%}.padded-right{padding-right:6%}}@media all and (min-width:37.5em){.padded-left{padding-left:4%}.padded-right{padding-right:4%}}@media all and (min-width:50em){.padded-left{padding-left:3.2%}.padded-right{padding-right:3.2%}}@media all and (min-width:64em){.padded-left{padding-left:3.1%}.padded-right{padding-right:3.1%}}@media all and (min-width:50em){.layout-tv .padded-left-withalphapicker{padding-left:4.5%}.layout-tv .padded-right-withalphapicker{padding-right:4.5%}}.searchfields-icon{color:#aaa}.button-accent-flat{color:#52B54B!important}.clearLink{text-decoration:none;font-weight:inherit!important;vertical-align:middle;color:inherit!important}.itemsViewSettingsContainer{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}@media all and (min-width:40em){.listIconButton-autohide{display:none!important}}@media all and (max-width:40em){.listTextButton-autohide{display:none!important}}.layout-tv .itemsViewSettingsContainer{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;padding:1.5em .75em 1em 0;font-size:92%}.itemsViewSettingsContainer>.button-flat{margin:0}
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/device.html b/MediaBrowser.WebDashboard/dashboard-ui/device.html
deleted file mode 100644
index 3623b8597d..0000000000
--- a/MediaBrowser.WebDashboard/dashboard-ui/device.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/devices.html b/MediaBrowser.WebDashboard/dashboard-ui/devices.html
index cc143e5f43..58825ed64e 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/devices.html
+++ b/MediaBrowser.WebDashboard/dashboard-ui/devices.html
@@ -1,21 +1,19 @@
-
+
-
-
${TabDevices}
+
+
${TabDevices}
-
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/dashboardpage.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/dashboardpage.js
index 826795f4d3..f9318cb292 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/dashboardpage.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/dashboardpage.js
@@ -1,2 +1,2 @@
-define(["datetime","jQuery","events","itemHelper","serverNotifications","dom","globalize","loading","connectionManager","playMethodHelper","cardBuilder","imageLoader","components/activitylog","humanedate","listViewStyle","emby-linkbutton","flexStyles","buttonenabled","emby-button","emby-itemscontainer"],function(datetime,$,events,itemHelper,serverNotifications,dom,globalize,loading,connectionManager,playMethodHelper,cardBuilder,imageLoader,ActivityLog){"use strict";function onConnectionHelpClick(e){return e.preventDefault(),!1}function onEditServerNameClick(e){var page=dom.parentWithClass(this,"page");return require(["prompt"],function(prompt){prompt({label:globalize.translate("LabelFriendlyServerName"),description:globalize.translate("LabelFriendlyServerNameHelp"),value:page.querySelector(".serverNameHeader").innerHTML,confirmText:globalize.translate("ButtonSave")}).then(function(value){loading.show(),ApiClient.getServerConfiguration().then(function(config){config.ServerName=value,ApiClient.updateServerConfiguration(config).then(function(){page.querySelector(".serverNameHeader").innerHTML=value,loading.hide()})})})}),e.preventDefault(),!1}function showPlaybackInfo(btn,session){require(["alert"],function(alert){var showTranscodeReasons,title,text=[],displayPlayMethod=playMethodHelper.getDisplayPlayMethod(session),isDirectStream="DirectStream"===displayPlayMethod,isTranscode="Transcode"===displayPlayMethod;isDirectStream?(title=globalize.translate("sharedcomponents#DirectStreaming"),text.push(globalize.translate("sharedcomponents#DirectStreamHelp1")),text.push("
"),text.push(globalize.translate("sharedcomponents#DirectStreamHelp2"))):isTranscode&&(title=globalize.translate("sharedcomponents#Transcoding"),text.push(globalize.translate("sharedcomponents#MediaIsBeingConverted")),session.TranscodingInfo&&session.TranscodingInfo.TranscodeReasons&&session.TranscodingInfo.TranscodeReasons.length&&(text.push("
"),text.push(globalize.translate("sharedcomponents#LabelReasonForTranscoding")),showTranscodeReasons=!0)),showTranscodeReasons&&session.TranscodingInfo.TranscodeReasons.forEach(function(t){text.push(globalize.translate("sharedcomponents#"+t))}),alert({text:text.join("
"),title:title})})}function showSendMessageForm(btn,session){require(["prompt"],function(prompt){prompt({title:globalize.translate("HeaderSendMessage"),label:globalize.translate("LabelMessageText"),confirmText:globalize.translate("ButtonSend")}).then(function(text){if(text){connectionManager.getApiClient(session.ServerId).sendMessageCommand(session.Id,{Text:text,TimeoutMs:5e3})}})})}function showOptionsMenu(btn,session){require(["actionsheet"],function(actionsheet){var menuItems=[];return session.ServerId&&session.DeviceId!==connectionManager.deviceId()&&menuItems.push({name:globalize.translate("SendMessage"),id:"sendmessage"}),session.TranscodingInfo&&session.TranscodingInfo.TranscodeReasons&&session.TranscodingInfo.TranscodeReasons.length&&menuItems.push({name:globalize.translate("ViewPlaybackInfo"),id:"transcodinginfo"}),actionsheet.show({items:menuItems,positionTo:btn}).then(function(id){switch(id){case"sendmessage":showSendMessageForm(btn,session);break;case"transcodinginfo":showPlaybackInfo(btn,session)}})})}function onActiveDevicesClick(e){var btn=dom.parentWithClass(e.target,"sessionCardButton");if(btn){var card=dom.parentWithClass(btn,"card");if(card){var sessionId=card.id,session=(DashboardPage.sessionsList||[]).filter(function(s){return"session"+s.Id===sessionId})[0];session&&(btn.classList.contains("btnCardOptions")?showOptionsMenu(btn,session):btn.classList.contains("btnSessionInfo")?showPlaybackInfo(btn,session):btn.classList.contains("btnSessionSendMessage")?showSendMessageForm(btn,session):btn.classList.contains("btnSessionStop")?connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id,"Stop"):btn.classList.contains("btnSessionPlayPause")&&session.PlayState&&connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id,"PlayPause"))}}}function filterSessions(sessions){for(var list=[],i=0,length=sessions.length;i
'+globalize.translate("PleaseUpdateManually")+""),DashboardPage.renderPaths(view,systemInfo),renderHasPendingRestart(view,apiClient,systemInfo.HasPendingRestart)})}function renderInfo(view,sessions,forceUpdate){sessions=filterSessions(sessions),renderActiveConnections(view,sessions),DashboardPage.renderPluginUpdateInfo(view,forceUpdate),loading.hide()}function pollForInfo(view,apiClient,forceUpdate){apiClient.getSessions().then(function(sessions){renderInfo(view,sessions,forceUpdate)}),apiClient.getScheduledTasks().then(function(tasks){renderRunningTasks(view,tasks)})}function renderActiveConnections(view,sessions){var html="";DashboardPage.sessionsList=sessions;var parentElement=view.querySelector(".activeDevices");$(".card",parentElement).addClass("deadSession");for(var i=0,length=sessions.length;i',html+='',html+='
',html+='
',html+='
';var imgUrl=DashboardPage.getNowPlayingImageUrl(nowPlayingItem);imgUrl?(html+='
",html+='
',html+='
';var clientImage=DashboardPage.getClientImage(session);clientImage&&(html+=clientImage),html+='
',html+='
'+session.DeviceName+"
",html+='
'+DashboardPage.getAppSecondaryText(session)+"
",html+="
",html+="
",html+='
'+DashboardPage.getSessionNowPlayingTime(session)+"
",session.TranscodingInfo&&session.TranscodingInfo.Framerate?html+='
'+session.TranscodingInfo.Framerate+" fps
":html+='
';var nowPlayingName=DashboardPage.getNowPlayingName(session);if(html+='
',html+=nowPlayingName.html,html+="
",nowPlayingItem&&nowPlayingItem.RunTimeTicks){html+='
'}else html+='
';session.TranscodingInfo&&session.TranscodingInfo.CompletionPercentage?html+='
':html+='
',html+="
",html+="
",html+="
",html+='",html+="
",html+=" "}}parentElement.insertAdjacentHTML("beforeend",html),$(".deadSession",parentElement).remove()}function renderRunningTasks(view,tasks){var html="";tasks=tasks.filter(function(t){return"Idle"!=t.State&&!t.IsHidden}),tasks.length?view.querySelector(".runningTasksContainer").classList.remove("hide"):view.querySelector(".runningTasksContainer").classList.add("hide"),tasks.filter(function(t){return t.Key==DashboardPage.systemUpdateTaskKey}).length?$("#btnUpdateApplication",view).buttonEnabled(!1):$("#btnUpdateApplication",view).buttonEnabled(!0);for(var i=0,length=tasks.length;i
",html+=task.Name+" ","Running"==task.State){var progress=(task.CurrentProgressPercentage||0).toFixed(1);html+='',html+=progress+"%",html+=" ",html+=""+progress+"% ",html+='cancel '}else"Cancelling"==task.State&&(html+=''+globalize.translate("LabelStopping")+" ");html+=""}view.querySelector("#divRunningTasks").innerHTML=html}return window.DashboardPage={newsStartIndex:0,renderPaths:function(page,systemInfo){$("#cachePath",page).html(systemInfo.CachePath),$("#logPath",page).html(systemInfo.LogPath),$("#transcodingTemporaryPath",page).html(systemInfo.TranscodingTempPath),$("#metadataPath",page).html(systemInfo.InternalMetadataPath)},reloadNews:function(page){var query={StartIndex:DashboardPage.newsStartIndex,Limit:4};ApiClient.getProductNews(query).then(function(result){var html=result.Items.map(function(item){var itemHtml="";itemHtml+='',itemHtml+='',itemHtml+='
dvr ',itemHtml+='
',itemHtml+='
',itemHtml+=item.Title,itemHtml+="
",itemHtml+='
';var date=datetime.parseISO8601Date(item.Date,!0);return itemHtml+=datetime.toLocaleDateString(date),itemHtml+="
",itemHtml+="
",itemHtml+="
",itemHtml+=" "});page.querySelector(".latestNewsItems").innerHTML=html.join("")})},startInterval:function(apiClient){apiClient.sendMessage("SessionsStart","0,1500"),apiClient.sendMessage("ScheduledTasksInfoStart","0,1000")},stopInterval:function(apiClient){apiClient.sendMessage("SessionsStop"),apiClient.sendMessage("ScheduledTasksInfoStop")},getSessionNowPlayingStreamInfo:function(session){var html="",showTranscodingInfo=!1,displayPlayMethod=playMethodHelper.getDisplayPlayMethod(session);if("DirectStream"===displayPlayMethod?(html+=globalize.translate("sharedcomponents#DirectStreaming"),!0):"Transcode"==displayPlayMethod?(html+=globalize.translate("sharedcomponents#Transcoding"),session.TranscodingInfo&&session.TranscodingInfo.Framerate&&(html+=" ("+session.TranscodingInfo.Framerate+" fps)"),showTranscodingInfo=!0,!0):"DirectPlay"==displayPlayMethod&&(html+=globalize.translate("sharedcomponents#DirectPlaying")),showTranscodingInfo){var line=[];session.TranscodingInfo&&(session.TranscodingInfo.Bitrate&&(session.TranscodingInfo.Bitrate>1e6?line.push((session.TranscodingInfo.Bitrate/1e6).toFixed(1)+" Mbps"):line.push(Math.floor(session.TranscodingInfo.Bitrate/1e3)+" kbps")),session.TranscodingInfo.Container&&line.push(session.TranscodingInfo.Container),session.TranscodingInfo.VideoCodec&&line.push(session.TranscodingInfo.VideoCodec),session.TranscodingInfo.AudioCodec&&session.TranscodingInfo.AudioCodec!=session.TranscodingInfo.Container&&line.push(session.TranscodingInfo.AudioCodec)),line.length&&(html+=" - "+line.join(" "))}return html||" "},getSessionNowPlayingTime:function(session){var nowPlayingItem=session.NowPlayingItem,html="";return nowPlayingItem?(session.PlayState.PositionTicks?html+=datetime.getDisplayRunningTime(session.PlayState.PositionTicks):html+="--:--:--",html+=" / ",nowPlayingItem&&nowPlayingItem.RunTimeTicks?html+=datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks):html+="--:--:--",html):html},getAppSecondaryText:function(session){return session.Client+" "+session.ApplicationVersion},getNowPlayingName:function(session){var imgUrl="",nowPlayingItem=session.NowPlayingItem;if(!nowPlayingItem)return{html:"Last seen "+humane_date(session.LastActivityDate),image:imgUrl};var topText=itemHelper.getDisplayName(nowPlayingItem),bottomText="";return nowPlayingItem.Artists&&nowPlayingItem.Artists.length?(bottomText=topText,topText=nowPlayingItem.Artists[0]):nowPlayingItem.SeriesName||nowPlayingItem.Album?(bottomText=topText,topText=nowPlayingItem.SeriesName||nowPlayingItem.Album):nowPlayingItem.ProductionYear&&(bottomText=nowPlayingItem.ProductionYear),nowPlayingItem.ImageTags&&nowPlayingItem.ImageTags.Logo?imgUrl=ApiClient.getScaledImageUrl(nowPlayingItem.Id,{tag:nowPlayingItem.ImageTags.Logo,maxHeight:24,maxWidth:130,type:"Logo"}):nowPlayingItem.ParentLogoImageTag&&(imgUrl=ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId,{tag:nowPlayingItem.ParentLogoImageTag,maxHeight:24,maxWidth:130,type:"Logo"})),imgUrl&&(topText=' '),{html:bottomText?topText+" "+bottomText:topText,image:imgUrl}},getUsersHtml:function(session){var html=[];session.UserId&&html.push(session.UserName);for(var i=0,length=session.AdditionalUsers.length;i ";if("dashboard"==clientLowered||"emby web client"==clientLowered){return" "}return-1!=clientLowered.indexOf("android")?" ":-1!=clientLowered.indexOf("ios")?" ":"mb-classic"==clientLowered?" ":"roku"==clientLowered?" ":"dlna"==clientLowered?" ":"kodi"==clientLowered||"xbmc"==clientLowered?" ":"chromecast"==clientLowered?" ":null},getNowPlayingImageUrl:function(item){if(item&&item.BackdropImageTags&&item.BackdropImageTags.length)return ApiClient.getScaledImageUrl(item.Id,{type:"Backdrop",width:275,tag:item.BackdropImageTags[0]});if(item&&item.ParentBackdropImageTags&&item.ParentBackdropImageTags.length)return ApiClient.getScaledImageUrl(item.ParentBackdropItemId,{type:"Backdrop",width:275,tag:item.ParentBackdropImageTags[0]});if(item&&item.BackdropImageTag)return ApiClient.getScaledImageUrl(item.BackdropItemId,{type:"Backdrop",width:275,tag:item.BackdropImageTag});var imageTags=(item||{}).ImageTags||{};return item&&imageTags.Thumb?ApiClient.getScaledImageUrl(item.Id,{type:"Thumb",width:275,tag:imageTags.Thumb}):item&&item.ParentThumbImageTag?ApiClient.getScaledImageUrl(item.ParentThumbItemId,{type:"Thumb",width:275,tag:item.ParentThumbImageTag}):item&&item.ThumbImageTag?ApiClient.getScaledImageUrl(item.ThumbItemId,{type:"Thumb",width:275,tag:item.ThumbImageTag}):item&&imageTags.Primary?ApiClient.getScaledImageUrl(item.Id,{type:"Primary",width:275,tag:imageTags.Primary}):item&&item.PrimaryImageTag?ApiClient.getScaledImageUrl(item.PrimaryImageItemId,{type:"Primary",width:275,tag:item.PrimaryImageTag}):null},systemUpdateTaskKey:"SystemUpdateTask",renderUrls:function(page,systemInfo){var helpButton=''+globalize.translate("ButtonHelp")+" ";if(systemInfo.LocalAddress){var localAccessHtml=globalize.translate("LabelLocalAccessUrl",''+systemInfo.LocalAddress+" ");$(".localUrl",page).html(localAccessHtml+helpButton).show()}else $(".externalUrl",page).hide();if(systemInfo.WanAddress){var externalUrl=systemInfo.WanAddress,remoteAccessHtml=globalize.translate("LabelRemoteAccessUrl",''+externalUrl+" ");$(".externalUrl",page).html(remoteAccessHtml+helpButton).show()}else $(".externalUrl",page).hide()},renderSupporterIcon:function(page,pluginSecurityInfo){var imgUrl,text,supporterIconContainer=page.querySelector(".supporterIconContainer");pluginSecurityInfo.IsMBSupporter?(supporterIconContainer.classList.remove("hide"),imgUrl="css/images/supporter/supporterbadge.png",text=globalize.translate("MessageThankYouForSupporting"),supporterIconContainer.innerHTML=' '):supporterIconContainer.classList.add("hide")},renderPendingInstallations:function(page,systemInfo){if(!systemInfo.CompletedInstallations.length)return void page.querySelector("#collapsiblePendingInstallations").classList.add("hide");page.querySelector("#collapsiblePendingInstallations").classList.remove("hide");for(var html="",i=0,length=systemInfo.CompletedInstallations.length;i"+update.Name+" ("+update.Version+") "}$("#pendingInstallations",page).html(html)},renderPluginUpdateInfo:function(page,forceUpdate){!forceUpdate&&DashboardPage.lastPluginUpdateCheck&&(new Date).getTime()-DashboardPage.lastPluginUpdateCheck<18e5||(DashboardPage.lastPluginUpdateCheck=(new Date).getTime(),ApiClient.getAvailablePluginUpdates().then(function(updates){var elem=page.querySelector("#pPluginUpdates");if(!updates.length)return void $(elem).hide();$(elem).show();for(var html="",i=0,length=updates.length;i
"+globalize.translate("NewVersionOfSomethingAvailable").replace("{0}",update.name)+" ",html+=''+globalize.translate("ButtonUpdateNow")+" "}elem.innerHTML=html}))},installPluginUpdate:function(button){$(button).buttonEnabled(!1);var name=button.getAttribute("data-name"),guid=button.getAttribute("data-guid"),version=button.getAttribute("data-version"),classification=button.getAttribute("data-classification");loading.show(),ApiClient.installPlugin(name,guid,classification,version).then(function(){loading.hide()})},updateApplication:function(){var page=$($.mobile.activePage)[0];$("#btnUpdateApplication",page).buttonEnabled(!1),loading.show(),ApiClient.getScheduledTasks().then(function(tasks){var task=tasks.filter(function(t){return t.Key==DashboardPage.systemUpdateTaskKey})[0];ApiClient.startScheduledTask(task.Id).then(function(){pollForInfo(page,ApiClient),loading.hide()})})},stopTask:function(id){var page=$($.mobile.activePage)[0];ApiClient.stopScheduledTask(id).then(function(){pollForInfo(page,ApiClient)})},restart:function(){require(["confirm"],function(confirm){confirm({title:globalize.translate("HeaderRestart"),text:globalize.translate("MessageConfirmRestart"),confirmText:globalize.translate("ButtonRestart"),primary:"cancel"}).then(function(){$("#btnRestartServer").buttonEnabled(!1),$("#btnShutdown").buttonEnabled(!1),Dashboard.restartServer()})})},shutdown:function(){require(["confirm"],function(confirm){confirm({title:globalize.translate("HeaderShutdown"),text:globalize.translate("MessageConfirmShutdown"),confirmText:globalize.translate("ButtonShutdown"),primary:"cancel"}).then(function(){$("#btnRestartServer").buttonEnabled(!1),$("#btnShutdown").buttonEnabled(!1),ApiClient.shutdownServer()})})}},pageClassOn("pageshow","type-interior",function(){var page=this;getPluginSecurityInfo().then(function(pluginSecurityInfo){if(!page.querySelector(".customSupporterPromotion")&&($(".supporterPromotion",page).remove(),!pluginSecurityInfo.IsMBSupporter)){var html='",page.querySelector(".content-primary").insertAdjacentHTML("afterbegin",html)}})}),function(view,params){function onRestartRequired(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onServerShuttingDown(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onServerRestarting(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onPackageInstalling(e,apiClient){apiClient.serverId()===serverId&&(pollForInfo(view,apiClient,!0),reloadSystemInfo(view,apiClient))}function onPackageInstallationCompleted(e,apiClient){apiClient.serverId()===serverId&&(pollForInfo(view,apiClient,!0),reloadSystemInfo(view,apiClient))}function onSessionsUpdate(e,apiClient,info){apiClient.serverId()===serverId&&renderInfo(view,info)}function onScheduledTasksUpdate(e,apiClient,info){apiClient.serverId()===serverId&&renderRunningTasks(view,info)}var serverId=ApiClient.serverId();view.querySelector(".btnConnectionHelp").addEventListener("click",onConnectionHelpClick),view.querySelector(".btnEditServerName").addEventListener("click",onEditServerNameClick),view.querySelector(".activeDevices").addEventListener("click",onActiveDevicesClick),view.addEventListener("viewshow",function(){var page=this,apiClient=ApiClient;apiClient&&(DashboardPage.newsStartIndex=0,loading.show(),pollForInfo(page,apiClient),DashboardPage.startInterval(apiClient),events.on(serverNotifications,"RestartRequired",onRestartRequired),events.on(serverNotifications,"ServerShuttingDown",onServerShuttingDown),events.on(serverNotifications,"ServerRestarting",onServerRestarting),events.on(serverNotifications,"PackageInstalling",onPackageInstalling),events.on(serverNotifications,"PackageInstallationCompleted",onPackageInstallationCompleted),events.on(serverNotifications,"Sessions",onSessionsUpdate),events.on(serverNotifications,"ScheduledTasksInfo",onScheduledTasksUpdate),DashboardPage.lastAppUpdateCheck=null,DashboardPage.lastPluginUpdateCheck=null,getPluginSecurityInfo().then(function(pluginSecurityInfo){DashboardPage.renderSupporterIcon(page,pluginSecurityInfo)}),reloadSystemInfo(page,ApiClient),DashboardPage.reloadNews(page),page.activityLog||(page.activityLog=new ActivityLog({serverId:ApiClient.serverId(),element:page.querySelector(".activityItems")})),page.querySelector(".swaggerLink").setAttribute("href","http://swagger.emby.media?url="+ApiClient.getUrl("swagger")),refreshActiveRecordings(view,apiClient))}),view.addEventListener("viewbeforehide",function(){var page=this,activityLog=page.activityLog;activityLog&&activityLog.destroy(),page.activityLog=null;var apiClient=ApiClient
-;events.off(serverNotifications,"RestartRequired",onRestartRequired),events.off(serverNotifications,"ServerShuttingDown",onServerShuttingDown),events.off(serverNotifications,"ServerRestarting",onServerRestarting),events.off(serverNotifications,"PackageInstalling",onPackageInstalling),events.off(serverNotifications,"PackageInstallationCompleted",onPackageInstallationCompleted),events.off(serverNotifications,"Sessions",onSessionsUpdate),events.off(serverNotifications,"ScheduledTasksInfo",onScheduledTasksUpdate),apiClient&&DashboardPage.stopInterval(apiClient)})}});
\ No newline at end of file
+define(["datetime","jQuery","events","itemHelper","serverNotifications","dom","globalize","loading","connectionManager","playMethodHelper","cardBuilder","imageLoader","components/activitylog","humanedate","listViewStyle","emby-linkbutton","flexStyles","buttonenabled","emby-button","emby-itemscontainer"],function(datetime,$,events,itemHelper,serverNotifications,dom,globalize,loading,connectionManager,playMethodHelper,cardBuilder,imageLoader,ActivityLog){"use strict";function onConnectionHelpClick(e){return e.preventDefault(),!1}function onEditServerNameClick(e){var page=dom.parentWithClass(this,"page");return require(["prompt"],function(prompt){prompt({label:globalize.translate("LabelFriendlyServerName"),description:globalize.translate("LabelFriendlyServerNameHelp"),value:page.querySelector(".serverNameHeader").innerHTML,confirmText:globalize.translate("ButtonSave")}).then(function(value){loading.show(),ApiClient.getServerConfiguration().then(function(config){config.ServerName=value,ApiClient.updateServerConfiguration(config).then(function(){page.querySelector(".serverNameHeader").innerHTML=value,loading.hide()})})})}),e.preventDefault(),!1}function showPlaybackInfo(btn,session){require(["alert"],function(alert){var showTranscodeReasons,title,text=[],displayPlayMethod=playMethodHelper.getDisplayPlayMethod(session),isDirectStream="DirectStream"===displayPlayMethod,isTranscode="Transcode"===displayPlayMethod;isDirectStream?(title=globalize.translate("sharedcomponents#DirectStreaming"),text.push(globalize.translate("sharedcomponents#DirectStreamHelp1")),text.push(" "),text.push(globalize.translate("sharedcomponents#DirectStreamHelp2"))):isTranscode&&(title=globalize.translate("sharedcomponents#Transcoding"),text.push(globalize.translate("sharedcomponents#MediaIsBeingConverted")),session.TranscodingInfo&&session.TranscodingInfo.TranscodeReasons&&session.TranscodingInfo.TranscodeReasons.length&&(text.push(" "),text.push(globalize.translate("sharedcomponents#LabelReasonForTranscoding")),showTranscodeReasons=!0)),showTranscodeReasons&&session.TranscodingInfo.TranscodeReasons.forEach(function(t){text.push(globalize.translate("sharedcomponents#"+t))}),alert({text:text.join(" "),title:title})})}function showSendMessageForm(btn,session){require(["prompt"],function(prompt){prompt({title:globalize.translate("HeaderSendMessage"),label:globalize.translate("LabelMessageText"),confirmText:globalize.translate("ButtonSend")}).then(function(text){if(text){connectionManager.getApiClient(session.ServerId).sendMessageCommand(session.Id,{Text:text,TimeoutMs:5e3})}})})}function showOptionsMenu(btn,session){require(["actionsheet"],function(actionsheet){var menuItems=[];return session.ServerId&&session.DeviceId!==connectionManager.deviceId()&&menuItems.push({name:globalize.translate("SendMessage"),id:"sendmessage"}),session.TranscodingInfo&&session.TranscodingInfo.TranscodeReasons&&session.TranscodingInfo.TranscodeReasons.length&&menuItems.push({name:globalize.translate("ViewPlaybackInfo"),id:"transcodinginfo"}),actionsheet.show({items:menuItems,positionTo:btn}).then(function(id){switch(id){case"sendmessage":showSendMessageForm(btn,session);break;case"transcodinginfo":showPlaybackInfo(btn,session)}})})}function onActiveDevicesClick(e){var btn=dom.parentWithClass(e.target,"sessionCardButton");if(btn){var card=dom.parentWithClass(btn,"card");if(card){var sessionId=card.id,session=(DashboardPage.sessionsList||[]).filter(function(s){return"session"+s.Id===sessionId})[0];session&&(btn.classList.contains("btnCardOptions")?showOptionsMenu(btn,session):btn.classList.contains("btnSessionInfo")?showPlaybackInfo(btn,session):btn.classList.contains("btnSessionSendMessage")?showSendMessageForm(btn,session):btn.classList.contains("btnSessionStop")?connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id,"Stop"):btn.classList.contains("btnSessionPlayPause")&&session.PlayState&&connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id,"PlayPause"))}}}function filterSessions(sessions){for(var list=[],minActiveDate=(new Date).getTime()-9e5,i=0,length=sessions.length;i=minActiveDate&&list.push(session)}}return list}function getPluginSecurityInfo(){var apiClient=window.ApiClient;return apiClient?connectionManager.getRegistrationInfo("themes",apiClient,{viewOnly:!0}).then(function(result){return{IsMBSupporter:!0}},function(){return{IsMBSupporter:!1}}):Promise.reject()}function refreshActiveRecordings(view,apiClient){apiClient.getLiveTvRecordings({UserId:Dashboard.getCurrentUserId(),IsInProgress:!0,Fields:"CanDelete,PrimaryImageAspectRatio",EnableTotalRecordCount:!1,EnableImageTypes:"Primary,Thumb,Backdrop"}).then(function(result){var itemsContainer=view.querySelector(".activeRecordingItems");if(!result.Items.length)return view.querySelector(".activeRecordingsSection").classList.add("hide"),void(itemsContainer.innerHTML="");view.querySelector(".activeRecordingsSection").classList.remove("hide");itemsContainer.innerHTML=cardBuilder.getCardsHtml({items:result.Items,shape:"auto",defaultShape:"backdrop",showTitle:!0,showParentTitle:!0,coverImage:!0,cardLayout:!1,centerText:!0,preferThumb:"auto",overlayText:!1,overlayMoreButton:!0,action:"none",centerPlayButton:!0}),imageLoader.lazyChildren(itemsContainer)})}function renderHasPendingRestart(view,apiClient,hasPendingRestart){if(hasPendingRestart)view.querySelector("#pUpToDate").classList.add("hide"),$("#pUpdateNow",view).hide();else{if(DashboardPage.lastAppUpdateCheck&&(new Date).getTime()-DashboardPage.lastAppUpdateCheck<18e5)return;DashboardPage.lastAppUpdateCheck=(new Date).getTime(),apiClient.getAvailableApplicationUpdate().then(function(packageInfo){var version=packageInfo[0];version?(view.querySelector("#pUpToDate").classList.add("hide"),$("#pUpdateNow",view).show(),$("#newVersionNumber",view).html(globalize.translate("VersionXIsAvailableForDownload").replace("{0}",version.versionStr))):(view.querySelector("#pUpToDate").classList.remove("hide"),$("#pUpdateNow",view).hide())})}}function reloadSystemInfo(view,apiClient){apiClient.getSystemInfo().then(function(systemInfo){view.querySelector(".serverNameHeader").innerHTML=systemInfo.ServerName;var localizedVersion=globalize.translate("LabelVersionNumber",systemInfo.Version);systemInfo.SystemUpdateLevel&&"Release"!=systemInfo.SystemUpdateLevel&&(localizedVersion+=" "+globalize.translate("Option"+systemInfo.SystemUpdateLevel).toLowerCase()),systemInfo.CanSelfRestart?$(".btnRestartContainer",view).removeClass("hide"):$(".btnRestartContainer",view).addClass("hide"),$("#appVersionNumber",view).html(localizedVersion),systemInfo.SupportsHttps?$("#ports",view).html(globalize.translate("LabelRunningOnPorts",systemInfo.HttpServerPortNumber,systemInfo.HttpsPortNumber)):$("#ports",view).html(globalize.translate("LabelRunningOnPort",systemInfo.HttpServerPortNumber)),DashboardPage.renderUrls(view,systemInfo),DashboardPage.renderPendingInstallations(view,systemInfo),systemInfo.CanSelfUpdate?($("#btnUpdateApplicationContainer",view).show(),$("#btnManualUpdateContainer",view).hide()):($("#btnUpdateApplicationContainer",view).hide(),$("#btnManualUpdateContainer",view).show()),"synology"==systemInfo.PackageName?$("#btnManualUpdateContainer").html(globalize.translate("SynologyUpdateInstructions")):$("#btnManualUpdateContainer").html(''+globalize.translate("PleaseUpdateManually")+" "),DashboardPage.renderPaths(view,systemInfo),renderHasPendingRestart(view,apiClient,systemInfo.HasPendingRestart)})}function renderInfo(view,sessions,forceUpdate){sessions=filterSessions(sessions),renderActiveConnections(view,sessions),DashboardPage.renderPluginUpdateInfo(view,forceUpdate),loading.hide()}function pollForInfo(view,apiClient,forceUpdate){apiClient.getSessions({ActiveWithinSeconds:960}).then(function(sessions){renderInfo(view,sessions,forceUpdate)}),apiClient.getScheduledTasks().then(function(tasks){renderRunningTasks(view,tasks)})}function renderActiveConnections(view,sessions){var html="";DashboardPage.sessionsList=sessions;var parentElement=view.querySelector(".activeDevices");$(".card",parentElement).addClass("deadSession");for(var i=0,length=sessions.length;i',html+='',html+='
',html+='
',html+='
';var imgUrl=DashboardPage.getNowPlayingImageUrl(nowPlayingItem);imgUrl?(html+='
",html+='
',html+='
';var clientImage=DashboardPage.getClientImage(session);clientImage&&(html+=clientImage),html+='
',html+='
'+session.DeviceName+"
",html+='
'+DashboardPage.getAppSecondaryText(session)+"
",html+="
",html+="
",html+='
'+DashboardPage.getSessionNowPlayingTime(session)+"
",session.TranscodingInfo&&session.TranscodingInfo.Framerate?html+='
'+session.TranscodingInfo.Framerate+" fps
":html+='
';var nowPlayingName=DashboardPage.getNowPlayingName(session);if(html+='
',html+=nowPlayingName.html,html+="
",nowPlayingItem&&nowPlayingItem.RunTimeTicks){html+='
'}else html+='
';session.TranscodingInfo&&session.TranscodingInfo.CompletionPercentage?html+='
':html+='
',html+="
",html+="
",html+="
",html+='",html+="
",html+=" "}}parentElement.insertAdjacentHTML("beforeend",html),$(".deadSession",parentElement).remove()}function renderRunningTasks(view,tasks){var html="";tasks=tasks.filter(function(t){return"Idle"!=t.State&&!t.IsHidden}),tasks.length?view.querySelector(".runningTasksContainer").classList.remove("hide"):view.querySelector(".runningTasksContainer").classList.add("hide"),tasks.filter(function(t){return t.Key==DashboardPage.systemUpdateTaskKey}).length?$("#btnUpdateApplication",view).buttonEnabled(!1):$("#btnUpdateApplication",view).buttonEnabled(!0);for(var i=0,length=tasks.length;i
",html+=task.Name+" ","Running"==task.State){var progress=(task.CurrentProgressPercentage||0).toFixed(1);html+='',html+=progress+"%",html+=" ",html+=""+progress+"% ",html+='cancel '}else"Cancelling"==task.State&&(html+=''+globalize.translate("LabelStopping")+" ");html+=""}view.querySelector("#divRunningTasks").innerHTML=html}return window.DashboardPage={newsStartIndex:0,renderPaths:function(page,systemInfo){$("#cachePath",page).html(systemInfo.CachePath),$("#logPath",page).html(systemInfo.LogPath),$("#transcodingTemporaryPath",page).html(systemInfo.TranscodingTempPath),$("#metadataPath",page).html(systemInfo.InternalMetadataPath)},reloadNews:function(page){var query={StartIndex:DashboardPage.newsStartIndex,Limit:4};ApiClient.getProductNews(query).then(function(result){var html=result.Items.map(function(item){var itemHtml="";itemHtml+='',itemHtml+='',itemHtml+='
dvr ',itemHtml+='
',itemHtml+='
',itemHtml+=item.Title,itemHtml+="
",itemHtml+='
';var date=datetime.parseISO8601Date(item.Date,!0);return itemHtml+=datetime.toLocaleDateString(date),itemHtml+="
",itemHtml+="
",itemHtml+="
",itemHtml+=" "});page.querySelector(".latestNewsItems").innerHTML=html.join("")})},startInterval:function(apiClient){apiClient.sendMessage("SessionsStart","0,1500"),apiClient.sendMessage("ScheduledTasksInfoStart","0,1000")},stopInterval:function(apiClient){apiClient.sendMessage("SessionsStop"),apiClient.sendMessage("ScheduledTasksInfoStop")},getSessionNowPlayingStreamInfo:function(session){var html="",showTranscodingInfo=!1,displayPlayMethod=playMethodHelper.getDisplayPlayMethod(session);if("DirectStream"===displayPlayMethod?(html+=globalize.translate("sharedcomponents#DirectStreaming"),!0):"Transcode"==displayPlayMethod?(html+=globalize.translate("sharedcomponents#Transcoding"),session.TranscodingInfo&&session.TranscodingInfo.Framerate&&(html+=" ("+session.TranscodingInfo.Framerate+" fps)"),showTranscodingInfo=!0,!0):"DirectPlay"==displayPlayMethod&&(html+=globalize.translate("sharedcomponents#DirectPlaying")),showTranscodingInfo){var line=[];session.TranscodingInfo&&(session.TranscodingInfo.Bitrate&&(session.TranscodingInfo.Bitrate>1e6?line.push((session.TranscodingInfo.Bitrate/1e6).toFixed(1)+" Mbps"):line.push(Math.floor(session.TranscodingInfo.Bitrate/1e3)+" kbps")),session.TranscodingInfo.Container&&line.push(session.TranscodingInfo.Container),session.TranscodingInfo.VideoCodec&&line.push(session.TranscodingInfo.VideoCodec),session.TranscodingInfo.AudioCodec&&session.TranscodingInfo.AudioCodec!=session.TranscodingInfo.Container&&line.push(session.TranscodingInfo.AudioCodec)),line.length&&(html+=" - "+line.join(" "))}return html||" "},getSessionNowPlayingTime:function(session){var nowPlayingItem=session.NowPlayingItem,html="";return nowPlayingItem?(session.PlayState.PositionTicks?html+=datetime.getDisplayRunningTime(session.PlayState.PositionTicks):html+="--:--:--",html+=" / ",nowPlayingItem&&nowPlayingItem.RunTimeTicks?html+=datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks):html+="--:--:--",html):html},getAppSecondaryText:function(session){return session.Client+" "+session.ApplicationVersion},getNowPlayingName:function(session){var imgUrl="",nowPlayingItem=session.NowPlayingItem;if(!nowPlayingItem)return{html:"Last seen "+humane_date(session.LastActivityDate),image:imgUrl};var topText=itemHelper.getDisplayName(nowPlayingItem),bottomText="";return nowPlayingItem.Artists&&nowPlayingItem.Artists.length?(bottomText=topText,topText=nowPlayingItem.Artists[0]):nowPlayingItem.SeriesName||nowPlayingItem.Album?(bottomText=topText,topText=nowPlayingItem.SeriesName||nowPlayingItem.Album):nowPlayingItem.ProductionYear&&(bottomText=nowPlayingItem.ProductionYear),nowPlayingItem.ImageTags&&nowPlayingItem.ImageTags.Logo?imgUrl=ApiClient.getScaledImageUrl(nowPlayingItem.Id,{tag:nowPlayingItem.ImageTags.Logo,maxHeight:24,maxWidth:130,type:"Logo"}):nowPlayingItem.ParentLogoImageTag&&(imgUrl=ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId,{tag:nowPlayingItem.ParentLogoImageTag,maxHeight:24,maxWidth:130,type:"Logo"})),imgUrl&&(topText=' '),{html:bottomText?topText+" "+bottomText:topText,image:imgUrl}},getUsersHtml:function(session){var html=[];session.UserId&&html.push(session.UserName);for(var i=0,length=session.AdditionalUsers.length;i ";if("dashboard"==clientLowered||"emby web client"==clientLowered){return" "}return-1!=clientLowered.indexOf("android")?" ":-1!=clientLowered.indexOf("ios")?" ":"mb-classic"==clientLowered?" ":"roku"==clientLowered?" ":"dlna"==clientLowered?" ":"kodi"==clientLowered||"xbmc"==clientLowered?" ":"chromecast"==clientLowered?" ":null},getNowPlayingImageUrl:function(item){if(item&&item.BackdropImageTags&&item.BackdropImageTags.length)return ApiClient.getScaledImageUrl(item.Id,{type:"Backdrop",width:275,tag:item.BackdropImageTags[0]});if(item&&item.ParentBackdropImageTags&&item.ParentBackdropImageTags.length)return ApiClient.getScaledImageUrl(item.ParentBackdropItemId,{type:"Backdrop",width:275,tag:item.ParentBackdropImageTags[0]});if(item&&item.BackdropImageTag)return ApiClient.getScaledImageUrl(item.BackdropItemId,{type:"Backdrop",width:275,tag:item.BackdropImageTag});var imageTags=(item||{}).ImageTags||{};return item&&imageTags.Thumb?ApiClient.getScaledImageUrl(item.Id,{type:"Thumb",width:275,tag:imageTags.Thumb}):item&&item.ParentThumbImageTag?ApiClient.getScaledImageUrl(item.ParentThumbItemId,{type:"Thumb",width:275,tag:item.ParentThumbImageTag}):item&&item.ThumbImageTag?ApiClient.getScaledImageUrl(item.ThumbItemId,{type:"Thumb",width:275,tag:item.ThumbImageTag}):item&&imageTags.Primary?ApiClient.getScaledImageUrl(item.Id,{type:"Primary",width:275,tag:imageTags.Primary}):item&&item.PrimaryImageTag?ApiClient.getScaledImageUrl(item.PrimaryImageItemId,{type:"Primary",width:275,tag:item.PrimaryImageTag}):null},systemUpdateTaskKey:"SystemUpdateTask",renderUrls:function(page,systemInfo){var helpButton=''+globalize.translate("ButtonHelp")+" ";if(systemInfo.LocalAddress){var localAccessHtml=globalize.translate("LabelLocalAccessUrl",''+systemInfo.LocalAddress+" ");$(".localUrl",page).html(localAccessHtml+helpButton).show()}else $(".externalUrl",page).hide();if(systemInfo.WanAddress){var externalUrl=systemInfo.WanAddress,remoteAccessHtml=globalize.translate("LabelRemoteAccessUrl",''+externalUrl+" ");$(".externalUrl",page).html(remoteAccessHtml+helpButton).show()}else $(".externalUrl",page).hide()},renderSupporterIcon:function(page,pluginSecurityInfo){var imgUrl,text,supporterIconContainer=page.querySelector(".supporterIconContainer");pluginSecurityInfo.IsMBSupporter?(supporterIconContainer.classList.remove("hide"),imgUrl="css/images/supporter/supporterbadge.png",text=globalize.translate("MessageThankYouForSupporting"),supporterIconContainer.innerHTML=' '):supporterIconContainer.classList.add("hide")},renderPendingInstallations:function(page,systemInfo){if(!systemInfo.CompletedInstallations.length)return void page.querySelector("#collapsiblePendingInstallations").classList.add("hide");page.querySelector("#collapsiblePendingInstallations").classList.remove("hide");for(var html="",i=0,length=systemInfo.CompletedInstallations.length;i"+update.Name+" ("+update.Version+") "}$("#pendingInstallations",page).html(html)},renderPluginUpdateInfo:function(page,forceUpdate){!forceUpdate&&DashboardPage.lastPluginUpdateCheck&&(new Date).getTime()-DashboardPage.lastPluginUpdateCheck<18e5||(DashboardPage.lastPluginUpdateCheck=(new Date).getTime(),ApiClient.getAvailablePluginUpdates().then(function(updates){var elem=page.querySelector("#pPluginUpdates");if(!updates.length)return void $(elem).hide();$(elem).show();for(var html="",i=0,length=updates.length;i"+globalize.translate("NewVersionOfSomethingAvailable").replace("{0}",update.name)+"
",html+=''+globalize.translate("ButtonUpdateNow")+" "}elem.innerHTML=html}))},installPluginUpdate:function(button){$(button).buttonEnabled(!1);var name=button.getAttribute("data-name"),guid=button.getAttribute("data-guid"),version=button.getAttribute("data-version"),classification=button.getAttribute("data-classification");loading.show(),ApiClient.installPlugin(name,guid,classification,version).then(function(){loading.hide()})},updateApplication:function(){var page=$($.mobile.activePage)[0];$("#btnUpdateApplication",page).buttonEnabled(!1),loading.show(),ApiClient.getScheduledTasks().then(function(tasks){var task=tasks.filter(function(t){return t.Key==DashboardPage.systemUpdateTaskKey})[0];ApiClient.startScheduledTask(task.Id).then(function(){pollForInfo(page,ApiClient),loading.hide()})})},stopTask:function(id){var page=$($.mobile.activePage)[0];ApiClient.stopScheduledTask(id).then(function(){pollForInfo(page,ApiClient)})},restart:function(){require(["confirm"],function(confirm){confirm({title:globalize.translate("HeaderRestart"),text:globalize.translate("MessageConfirmRestart"),confirmText:globalize.translate("ButtonRestart"),primary:"cancel"}).then(function(){$("#btnRestartServer").buttonEnabled(!1),$("#btnShutdown").buttonEnabled(!1),Dashboard.restartServer()})})},shutdown:function(){require(["confirm"],function(confirm){confirm({title:globalize.translate("HeaderShutdown"),text:globalize.translate("MessageConfirmShutdown"),confirmText:globalize.translate("ButtonShutdown"),primary:"cancel"}).then(function(){$("#btnRestartServer").buttonEnabled(!1),$("#btnShutdown").buttonEnabled(!1),ApiClient.shutdownServer()})})}},pageClassOn("pageshow","type-interior",function(){var page=this;getPluginSecurityInfo().then(function(pluginSecurityInfo){if(!page.querySelector(".customSupporterPromotion")&&($(".supporterPromotion",page).remove(),!pluginSecurityInfo.IsMBSupporter)){var html='",page.querySelector(".content-primary").insertAdjacentHTML("afterbegin",html)}})}),function(view,params){function onRestartRequired(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onServerShuttingDown(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onServerRestarting(e,apiClient){apiClient.serverId()===serverId&&renderHasPendingRestart(view,apiClient,!0)}function onPackageInstalling(e,apiClient){apiClient.serverId()===serverId&&(pollForInfo(view,apiClient,!0),reloadSystemInfo(view,apiClient))}function onPackageInstallationCompleted(e,apiClient){apiClient.serverId()===serverId&&(pollForInfo(view,apiClient,!0),reloadSystemInfo(view,apiClient))}function onSessionsUpdate(e,apiClient,info){apiClient.serverId()===serverId&&renderInfo(view,info)}function onScheduledTasksUpdate(e,apiClient,info){apiClient.serverId()===serverId&&renderRunningTasks(view,info)}var serverId=ApiClient.serverId();view.querySelector(".btnConnectionHelp").addEventListener("click",onConnectionHelpClick),view.querySelector(".btnEditServerName").addEventListener("click",onEditServerNameClick),view.querySelector(".activeDevices").addEventListener("click",onActiveDevicesClick),view.addEventListener("viewshow",function(){var page=this,apiClient=ApiClient;apiClient&&(DashboardPage.newsStartIndex=0,loading.show(),pollForInfo(page,apiClient),DashboardPage.startInterval(apiClient),events.on(serverNotifications,"RestartRequired",onRestartRequired),events.on(serverNotifications,"ServerShuttingDown",onServerShuttingDown),events.on(serverNotifications,"ServerRestarting",onServerRestarting),events.on(serverNotifications,"PackageInstalling",onPackageInstalling),events.on(serverNotifications,"PackageInstallationCompleted",onPackageInstallationCompleted),events.on(serverNotifications,"Sessions",onSessionsUpdate),events.on(serverNotifications,"ScheduledTasksInfo",onScheduledTasksUpdate),DashboardPage.lastAppUpdateCheck=null,DashboardPage.lastPluginUpdateCheck=null,getPluginSecurityInfo().then(function(pluginSecurityInfo){DashboardPage.renderSupporterIcon(page,pluginSecurityInfo)}),reloadSystemInfo(page,ApiClient),DashboardPage.reloadNews(page),page.activityLog||(page.activityLog=new ActivityLog({serverId:ApiClient.serverId(),element:page.querySelector(".activityItems")})),page.querySelector(".swaggerLink").setAttribute("href","http://swagger.emby.media?url="+ApiClient.getUrl("swagger")),refreshActiveRecordings(view,apiClient))}),
+view.addEventListener("viewbeforehide",function(){var page=this,activityLog=page.activityLog;activityLog&&activityLog.destroy(),page.activityLog=null;var apiClient=ApiClient;events.off(serverNotifications,"RestartRequired",onRestartRequired),events.off(serverNotifications,"ServerShuttingDown",onServerShuttingDown),events.off(serverNotifications,"ServerRestarting",onServerRestarting),events.off(serverNotifications,"PackageInstalling",onPackageInstalling),events.off(serverNotifications,"PackageInstallationCompleted",onPackageInstallationCompleted),events.off(serverNotifications,"Sessions",onSessionsUpdate),events.off(serverNotifications,"ScheduledTasksInfo",onScheduledTasksUpdate),apiClient&&DashboardPage.stopInterval(apiClient)})}});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/device.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/device.js
deleted file mode 100644
index 76529dfa65..0000000000
--- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/device.js
+++ /dev/null
@@ -1 +0,0 @@
-define(["jQuery","loading","libraryMenu"],function($,loading,libraryMenu){"use strict";function load(page,device,capabilities){capabilities.SupportsContentUploading?$("#fldCameraUploadPath",page).removeClass("hide"):$("#fldCameraUploadPath",page).addClass("hide"),$("#txtCustomName",page).val(device.CustomName||""),$("#txtUploadPath",page).val(device.CameraUploadPath||""),$(".reportedName",page).html(device.ReportedName||"")}function loadData(page){loading.show();var id=getParameterByName("id"),promise1=ApiClient.getJSON(ApiClient.getUrl("Devices/Info",{Id:id})),promise2=ApiClient.getJSON(ApiClient.getUrl("Devices/Capabilities",{Id:id}));Promise.all([promise1,promise2]).then(function(responses){load(page,responses[0],responses[1]),loading.hide()})}function save(page){var id=getParameterByName("id");ApiClient.ajax({url:ApiClient.getUrl("Devices/Options",{Id:id}),type:"POST",data:JSON.stringify({CustomName:$("#txtCustomName",page).val(),CameraUploadPath:$("#txtUploadPath",page).val()}),contentType:"application/json"}).then(Dashboard.processServerConfigurationUpdateResult)}function onSubmit(){return save($(this).parents(".page")),!1}$(document).on("pageinit","#devicePage",function(){var page=this;$("#btnSelectUploadPath",page).on("click.selectDirectory",function(){require(["directorybrowser"],function(directoryBrowser){var picker=new directoryBrowser;picker.show({callback:function(path){path&&$("#txtUploadPath",page).val(path),picker.close()},validateWriteable:!0,header:Globalize.translate("HeaderSelectUploadPath")})})}),$(".deviceForm").off("submit",onSubmit).on("submit",onSubmit)}).on("pageshow","#devicePage",function(){loadData(this)})});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/devices.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/devices.js
index 6c19dea426..0c5e96d3a6 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/devices.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/devices.js
@@ -1 +1 @@
-define(["jQuery","loading","libraryMenu","globalize","listViewStyle","emby-linkbutton"],function($,loading,libraryMenu,globalize){"use strict";function deleteDevice(page,id){var msg=globalize.translate("DeleteDeviceConfirmation");require(["confirm"],function(confirm){confirm({text:msg,title:globalize.translate("HeaderDeleteDevice"),confirmText:globalize.translate("ButtonDelete"),primary:"cancel"}).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("Devices",{Id:id})}).then(function(){loadData(page)})})})}function load(page,devices){var html="";devices.length&&(html+=''),html+=devices.map(function(d){var deviceHtml="";return deviceHtml+='
',deviceHtml+='
tablet_android ',d.AppName&&d.LastUserName?deviceHtml+='
':deviceHtml+='
',deviceHtml+='
',deviceHtml+='',deviceHtml+=d.Name,deviceHtml+="
",d.AppName&&(deviceHtml+='',deviceHtml+=d.AppName,deviceHtml+="
"),d.LastUserName&&(deviceHtml+='',deviceHtml+=globalize.translate("DeviceLastUsedByUserName",d.LastUserName),deviceHtml+="
"),deviceHtml+=" ",deviceHtml+="
",deviceHtml+='
delete ',deviceHtml+="
"}).join(""),devices.length&&(html+="
");var elem=$(".devicesList",page).html(html).trigger("create");$(".btnDeleteDevice",elem).on("click",function(){deleteDevice(page,this.getAttribute("data-id"))})}function loadData(page){loading.show(),ApiClient.getJSON(ApiClient.getUrl("Devices",{SupportsPersistentIdentifier:!0})).then(function(result){load(page,result.Items),loading.hide()})}$(document).on("pageshow","#devicesPage",function(){loadData(this)})});
\ No newline at end of file
+define(["loading","dom","libraryMenu","globalize","humanedate","emby-linkbutton","emby-itemscontainer","cardStyle"],function(loading,dom,libraryMenu,globalize){"use strict";function deleteDevice(page,id){var msg=globalize.translate("DeleteDeviceConfirmation");require(["confirm"],function(confirm){confirm({text:msg,title:globalize.translate("HeaderDeleteDevice"),confirmText:globalize.translate("ButtonDelete"),primary:"cancel"}).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("Devices",{Id:id})}).then(function(){loadData(page)})})})}function load(page,devices){var html="";html+=devices.map(function(device){var deviceHtml="";return deviceHtml+="
",deviceHtml+='
',deviceHtml+='
',deviceHtml+='
',deviceHtml+='
',device.ImageUrl?(deviceHtml+='
",deviceHtml+="
"):deviceHtml+='
tablet_android ',deviceHtml+="
",deviceHtml+="
",deviceHtml+='",deviceHtml+="
",deviceHtml+="
"}).join(""),page.querySelector(".devicesList").innerHTML=html}function loadData(page){loading.show(),ApiClient.getJSON(ApiClient.getUrl("Devices")).then(function(result){load(page,result.Items),loading.hide()})}return function(view,params){view.querySelector(".devicesList").addEventListener("click",function(e){var btnDelete=dom.parentWithClass(e.target,"btnDeleteDevice");btnDelete&&deleteDevice(view,btnDelete.getAttribute("data-id"))}),view.addEventListener("viewshow",function(){loadData(this)})}});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/itembynamedetailpage.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/itembynamedetailpage.js
index c5912d8865..621070a4fe 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/itembynamedetailpage.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/itembynamedetailpage.js
@@ -1 +1 @@
-define(["connectionManager","listView","cardBuilder","imageLoader","libraryBrowser","emby-itemscontainer","emby-linkbutton"],function(connectionManager,listView,cardBuilder,imageLoader,libraryBrowser){"use strict";function renderItems(page,item){var sections=[];item.ArtistCount&§ions.push({name:Globalize.translate("TabArtists"),type:"MusicArtist"}),item.ProgramCount&&"Person"==item.Type&§ions.push({name:Globalize.translate("HeaderUpcomingOnTV"),type:"Program"}),item.MovieCount&§ions.push({name:Globalize.translate("TabMovies"),type:"Movie"}),item.SeriesCount&§ions.push({name:Globalize.translate("TabShows"),type:"Series"}),item.EpisodeCount&§ions.push({name:Globalize.translate("TabEpisodes"),type:"Episode"}),item.TrailerCount&§ions.push({name:Globalize.translate("TabTrailers"),type:"Trailer"}),item.GameCount&§ions.push({name:Globalize.translate("TabGames"),type:"Game"}),item.AlbumCount&§ions.push({name:Globalize.translate("TabAlbums"),type:"MusicAlbum"}),item.SongCount&§ions.push({name:Globalize.translate("TabSongs"),type:"Audio"}),item.MusicVideoCount&§ions.push({name:Globalize.translate("TabMusicVideos"),type:"MusicVideo"});var elem=page.querySelector("#childrenContent");elem.innerHTML=sections.map(function(section){var html="",sectionClass="verticalSection";return"Audio"===section.type&&(sectionClass+=" verticalSection-extrabottompadding"),html+='
',html+='
",html+='
',html+="
",html+="
"}).join("");for(var sectionElems=elem.querySelectorAll(".verticalSection"),i=0,length=sectionElems.length;i
query.Limit){var link=element.querySelector("a");link.classList.remove("hide"),link.setAttribute("href",getMoreItemsHref(item,type))}else element.querySelector("a").classList.add("hide");listOptions.items=result.Items;var itemsContainer=element.querySelector(".itemsContainer");"Audio"==type?(html=listView.getListViewHtml(listOptions),itemsContainer.classList.remove("vertical-wrap"),itemsContainer.classList.add("vertical-list")):(html=cardBuilder.getCardsHtml(listOptions),itemsContainer.classList.add("vertical-wrap"),itemsContainer.classList.remove("vertical-list")),itemsContainer.innerHTML=html,imageLoader.lazyChildren(itemsContainer)})}function getMoreItemsHref(item,type){return"Genre"==item.Type?"list.html?type="+type+"&genreId="+item.Id+"&serverId="+item.ServerId:"MusicGenre"==item.Type?"list.html?type="+type+"&musicGenreId="+item.Id+"&serverId="+item.ServerId:"GameGenre"==item.Type?"list.html?type="+type+"&gameGenreId="+item.Id+"&serverId="+item.ServerId:"Studio"==item.Type?"list.html?type="+type+"&studioId="+item.Id+"&serverId="+item.ServerId:"MusicArtist"==item.Type?"list.html?type="+type+"&artistId="+item.Id+"&serverId="+item.ServerId:"Person"==item.Type?"list.html?type="+type+"&personId="+item.Id+"&serverId="+item.ServerId:"list.html?type="+type+"&parentId="+item.Id+"&serverId="+item.ServerId}function addCurrentItemToQuery(query,item){"Person"==item.Type?query.PersonIds=item.Id:"Genre"==item.Type?query.GenreIds=item.Id:"MusicGenre"==item.Type?query.GenreIds=item.Id:"GameGenre"==item.Type?query.GenreIds=item.Id:"Studio"==item.Type?query.StudioIds=item.Id:"MusicArtist"==item.Type&&(query.ArtistIds=item.Id)}function getQuery(options,item){var query={SortOrder:"Ascending",IncludeItemTypes:"",Recursive:!0,Fields:"AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo",Limit:libraryBrowser.getDefaultPageSize(),StartIndex:0,CollapseBoxSetItems:!1};return query=Object.assign(query,options||{}),addCurrentItemToQuery(query,item),query}function getItemsFunction(options,item){var query=getQuery(options,item);return function(index,limit,fields){query.StartIndex=index,query.Limit=limit,fields&&(query.Fields+=","+fields);var apiClient=connectionManager.getApiClient(item.ServerId);return"MusicArtist"===query.IncludeItemTypes?(query.IncludeItemTypes=null,apiClient.getAlbumArtists(apiClient.getCurrentUserId(),query)):apiClient.getItems(apiClient.getCurrentUserId(),query)}}window.ItemsByName={renderItems:renderItems}});
\ No newline at end of file
+define(["connectionManager","listView","cardBuilder","imageLoader","libraryBrowser","emby-itemscontainer","emby-linkbutton"],function(connectionManager,listView,cardBuilder,imageLoader,libraryBrowser){"use strict";function renderItems(page,item){var sections=[];item.ArtistCount&§ions.push({name:Globalize.translate("TabArtists"),type:"MusicArtist"}),item.ProgramCount&&"Person"==item.Type&§ions.push({name:Globalize.translate("HeaderUpcomingOnTV"),type:"Program"}),item.MovieCount&§ions.push({name:Globalize.translate("TabMovies"),type:"Movie"}),item.SeriesCount&§ions.push({name:Globalize.translate("TabShows"),type:"Series"}),item.EpisodeCount&§ions.push({name:Globalize.translate("TabEpisodes"),type:"Episode"}),item.TrailerCount&§ions.push({name:Globalize.translate("TabTrailers"),type:"Trailer"}),item.GameCount&§ions.push({name:Globalize.translate("TabGames"),type:"Game"}),item.AlbumCount&§ions.push({name:Globalize.translate("TabAlbums"),type:"MusicAlbum"}),item.MusicVideoCount&§ions.push({name:Globalize.translate("TabMusicVideos"),type:"MusicVideo"});var elem=page.querySelector("#childrenContent");elem.innerHTML=sections.map(function(section){var html="",sectionClass="verticalSection";return"Audio"===section.type&&(sectionClass+=" verticalSection-extrabottompadding"),html+='',html+='
",html+='
',html+="
",html+="
"}).join("");for(var sectionElems=elem.querySelectorAll(".verticalSection"),i=0,length=sectionElems.length;iquery.Limit){var link=element.querySelector("a");link.classList.remove("hide"),link.setAttribute("href",getMoreItemsHref(item,type))}else element.querySelector("a").classList.add("hide");listOptions.items=result.Items;var itemsContainer=element.querySelector(".itemsContainer");"Audio"==type?(html=listView.getListViewHtml(listOptions),itemsContainer.classList.remove("vertical-wrap"),itemsContainer.classList.add("vertical-list")):(html=cardBuilder.getCardsHtml(listOptions),itemsContainer.classList.add("vertical-wrap"),itemsContainer.classList.remove("vertical-list")),itemsContainer.innerHTML=html,imageLoader.lazyChildren(itemsContainer)})}function getMoreItemsHref(item,type){return"Genre"==item.Type?"list.html?type="+type+"&genreId="+item.Id+"&serverId="+item.ServerId:"MusicGenre"==item.Type?"list.html?type="+type+"&musicGenreId="+item.Id+"&serverId="+item.ServerId:"GameGenre"==item.Type?"list.html?type="+type+"&gameGenreId="+item.Id+"&serverId="+item.ServerId:"Studio"==item.Type?"list.html?type="+type+"&studioId="+item.Id+"&serverId="+item.ServerId:"MusicArtist"==item.Type?"list.html?type="+type+"&artistId="+item.Id+"&serverId="+item.ServerId:"Person"==item.Type?"list.html?type="+type+"&personId="+item.Id+"&serverId="+item.ServerId:"list.html?type="+type+"&parentId="+item.Id+"&serverId="+item.ServerId}function addCurrentItemToQuery(query,item){"Person"==item.Type?query.PersonIds=item.Id:"Genre"==item.Type?query.GenreIds=item.Id:"MusicGenre"==item.Type?query.GenreIds=item.Id:"GameGenre"==item.Type?query.GenreIds=item.Id:"Studio"==item.Type?query.StudioIds=item.Id:"MusicArtist"==item.Type&&(connectionManager.getApiClient(item.ServerId).isMinServerVersion("3.4.1.18")?query.AlbumArtistIds=item.Id:query.ArtistIds=item.Id)}function getQuery(options,item){var query={SortOrder:"Ascending",IncludeItemTypes:"",Recursive:!0,Fields:"AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo",Limit:libraryBrowser.getDefaultPageSize(),StartIndex:0,CollapseBoxSetItems:!1};return query=Object.assign(query,options||{}),addCurrentItemToQuery(query,item),query}function getItemsFunction(options,item){var query=getQuery(options,item);return function(index,limit,fields){query.StartIndex=index,query.Limit=limit,fields&&(query.Fields+=","+fields);var apiClient=connectionManager.getApiClient(item.ServerId);return"MusicArtist"===query.IncludeItemTypes?(query.IncludeItemTypes=null,apiClient.getAlbumArtists(apiClient.getCurrentUserId(),query)):apiClient.getItems(apiClient.getCurrentUserId(),query)}}window.ItemsByName={renderItems:renderItems}});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/itemdetailpage.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/itemdetailpage.js
index 8c51cbc67c..c9de0708fb 100644
--- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/itemdetailpage.js
+++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/itemdetailpage.js
@@ -1,2 +1,2 @@
-define(["loading","appRouter","layoutManager","connectionManager","cardBuilder","datetime","mediaInfo","backdrop","listView","itemContextMenu","itemHelper","dom","indicators","apphost","imageLoader","libraryMenu","globalize","browser","events","scrollHelper","playbackManager","libraryBrowser","scrollStyles","emby-itemscontainer","emby-checkbox","emby-linkbutton","emby-playstatebutton","emby-ratingbutton","emby-downloadbutton","emby-scroller","emby-select"],function(loading,appRouter,layoutManager,connectionManager,cardBuilder,datetime,mediaInfo,backdrop,listView,itemContextMenu,itemHelper,dom,indicators,appHost,imageLoader,libraryMenu,globalize,browser,events,scrollHelper,playbackManager,libraryBrowser){"use strict";function getPromise(apiClient,params){var id=params.id;if(id)return apiClient.getItem(apiClient.getCurrentUserId(),id);if(params.seriesTimerId)return apiClient.getLiveTvSeriesTimer(params.seriesTimerId);var name=params.genre;if(name)return apiClient.getGenre(name,apiClient.getCurrentUserId());if(name=params.musicgenre)return apiClient.getMusicGenre(name,apiClient.getCurrentUserId());if(name=params.gamegenre)return apiClient.getGameGenre(name,apiClient.getCurrentUserId());if(name=params.musicartist)return apiClient.getArtist(name,apiClient.getCurrentUserId());throw new Error("Invalid request")}function hideAll(page,className,show){var i,length,elems=page.querySelectorAll("."+className);for(i=0,length=elems.length;i',html+=listView.getListViewHtml({items:items,enableUserDataButtons:!1,image:!0,imageSource:"channel",showProgramDateTime:!0,showChannel:!1,mediaInfo:!1,action:"none",moreButton:!1,recordButton:!1}),html+=" "}function renderSeriesTimerSchedule(page,apiClient,seriesTimerId){apiClient.getLiveTvTimers({UserId:apiClient.getCurrentUserId(),ImageTypeLimit:1,EnableImageTypes:"Primary,Backdrop,Thumb",SortBy:"StartDate",EnableTotalRecordCount:!1,EnableUserData:!1,SeriesTimerId:seriesTimerId,Fields:"ChannelInfo,ChannelImage"}).then(function(result){result.Items.length&&result.Items[0].SeriesTimerId!=seriesTimerId&&(result.Items=[]);var html=getProgramScheduleHtml(result.Items),scheduleTab=page.querySelector(".seriesTimerSchedule");scheduleTab.innerHTML=html,imageLoader.lazyChildren(scheduleTab)})}function renderTimerEditor(page,item,apiClient,user){if("Recording"!==item.Type||!user.Policy.EnableLiveTvManagement||!item.TimerId||"InProgress"!==item.Status)return void hideAll(page,"btnCancelTimer");hideAll(page,"btnCancelTimer",!0)}function renderSeriesTimerEditor(page,item,apiClient,user){return"SeriesTimer"!==item.Type?void hideAll(page,"btnCancelSeriesTimer"):user.Policy.EnableLiveTvManagement?(require(["seriesRecordingEditor"],function(seriesRecordingEditor){seriesRecordingEditor.embed(item,apiClient.serverId(),{context:page.querySelector(".seriesRecordingEditor")})}),page.querySelector(".seriesTimerScheduleSection").classList.remove("hide"),hideAll(page,"btnCancelSeriesTimer",!0),void renderSeriesTimerSchedule(page,apiClient,item.Id)):(page.querySelector(".seriesTimerScheduleSection").classList.add("hide"),void hideAll(page,"btnCancelSeriesTimer"))}function renderTrackSelections(page,instance,item){var select=page.querySelector(".selectSource");if(!item.MediaSources||!itemHelper.supportsMediaSourceSelection(item)||-1===playbackManager.getSupportedCommands().indexOf("PlayMediaSource")||!playbackManager.canPlay(item))return page.querySelector(".trackSelections").classList.add("hide"),select.innerHTML="",page.querySelector(".selectVideo").innerHTML="",page.querySelector(".selectAudio").innerHTML="",void(page.querySelector(".selectSubtitles").innerHTML="");playbackManager.getPlaybackMediaSources(item).then(function(mediaSources){instance._currentPlaybackMediaSources=mediaSources,page.querySelector(".trackSelections").classList.remove("hide"),select.setLabel(globalize.translate("sharedcomponents#LabelVersion"));var currentValue=select.value,selectedId=mediaSources[0].Id;select.innerHTML=mediaSources.map(function(v){var selected=v.Id===selectedId?" selected":"";return'"+v.Name+" "}).join(""),mediaSources.length>1?page.querySelector(".selectSourceContainer").classList.remove("hide"):page.querySelector(".selectSourceContainer").classList.add("hide"),select.value!==currentValue&&(renderVideoSelections(page,mediaSources),renderAudioSelections(page,mediaSources),renderSubtitleSelections(page,mediaSources))})}function renderVideoSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Video"===m.Type}),select=page.querySelector(".selectVideo");select.setLabel(globalize.translate("sharedcomponents#LabelVideo"));var selectedId=tracks.length?tracks[0].Index:-1;select.innerHTML=tracks.map(function(v){var selected=v.Index===selectedId?" selected":"",titleParts=[],resolutionText=mediaInfo.getResolutionText(v);return resolutionText&&titleParts.push(resolutionText),v.Codec&&titleParts.push(v.Codec.toUpperCase()),'"+(v.DisplayTitle||titleParts.join(" "))+" "}).join(""),select.setAttribute("disabled","disabled"),tracks.length?page.querySelector(".selectVideoContainer").classList.remove("hide"):page.querySelector(".selectVideoContainer").classList.add("hide")}function renderAudioSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Audio"===m.Type}),select=page.querySelector(".selectAudio");select.setLabel(globalize.translate("sharedcomponents#LabelAudio"));var selectedId=mediaSource.DefaultAudioStreamIndex;select.innerHTML=tracks.map(function(v){var selected=v.Index===selectedId?" selected":"";return'"+v.DisplayTitle+" "}).join(""),tracks.length>1?select.removeAttribute("disabled"):select.setAttribute("disabled","disabled"),tracks.length?page.querySelector(".selectAudioContainer").classList.remove("hide"):page.querySelector(".selectAudioContainer").classList.add("hide")}function renderSubtitleSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Subtitle"===m.Type}),select=page.querySelector(".selectSubtitles");select.setLabel(globalize.translate("sharedcomponents#LabelSubtitles"));var selectedId=null==mediaSource.DefaultSubtitleStreamIndex?-1:mediaSource.DefaultSubtitleStreamIndex;if(tracks.length){var selected=-1===selectedId?" selected":"";select.innerHTML=''+globalize.translate("sharedcomponents#Off")+" "+tracks.map(function(v){return selected=v.Index===selectedId?" selected":"",'"+v.DisplayTitle+" "}).join(""),page.querySelector(".selectSubtitlesContainer").classList.remove("hide")}else select.innerHTML="",page.querySelector(".selectSubtitlesContainer").classList.add("hide")}function reloadPlayButtons(page,item){var canPlay=!1;if("Program"==item.Type){var now=new Date;now>=datetime.parseISO8601Date(item.StartDate,!0)&&now0)}else hideAll(page,"btnPlay"),hideAll(page,"btnResume"),hideAll(page,"btnInstantMix"),hideAll(page,"btnShuffle");return canPlay}function reloadUserDataButtons(page,item){var i,length,btnPlaystates=page.querySelectorAll(".btnPlaystate");for(i=0,length=btnPlaystates.length;i'+artist.Name+"")}return html=html.join(" / ")}function renderName(item,container,isStatic,context){var parentRoute,parentNameHtml=[],parentNameLast=!1;item.AlbumArtists?(parentNameHtml.push(getArtistLinksHtml(item.AlbumArtists,item.ServerId,context)),parentNameLast=!0):item.ArtistItems&&item.ArtistItems.length&&"MusicVideo"===item.Type?(parentNameHtml.push(getArtistLinksHtml(item.ArtistItems,item.ServerId,context)),parentNameLast=!0):item.SeriesName&&"Episode"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeriesId,Name:item.SeriesName,Type:"Series",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeriesName+" ")):(item.IsSeries||item.EpisodeTitle)&&parentNameHtml.push(item.Name),item.SeriesName&&"Season"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeriesId,Name:item.SeriesName,Type:"Series",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeriesName+" ")):null!=item.ParentIndexNumber&&"Episode"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeasonId,Name:item.SeasonName,Type:"Season",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeasonName+" ")):null!=item.ParentIndexNumber&&item.IsSeries?parentNameHtml.push(item.SeasonName||"S"+item.ParentIndexNumber):item.Album&&"Audio"===item.Type&&(item.AlbumId||item.ParentId)?(parentRoute=appRouter.getRouteUrl({Id:item.AlbumId||item.ParentId,Name:item.Album,Type:"MusicAlbum",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.Album+" ")):item.Album&&"MusicVideo"===item.Type&&item.AlbumId?(parentRoute=appRouter.getRouteUrl({Id:item.Albumid,Name:item.Album,Type:"MusicAlbum",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.Album+" ")):item.Album&&parentNameHtml.push(item.Album);var html="";parentNameHtml.length&&(html=parentNameLast?''+parentNameHtml.join(" - ")+" ":''+parentNameHtml.join(" - ")+" ");var name=itemHelper.getDisplayName(item,{includeParentInfo:!1});html&&!parentNameLast?html+=''+name+" ":html=parentNameLast?''+name+" "+html:''+name+" "+html,container.innerHTML=html,html.length?container.classList.remove("hide"):container.classList.add("hide")}function setTrailerButtonVisibility(page,item){(item.LocalTrailerCount||item.RemoteTrailers&&item.RemoteTrailers.length)&&-1!==playbackManager.getSupportedCommands().indexOf("PlayTrailers")?hideAll(page,"btnPlayTrailer",!0):hideAll(page,"btnPlayTrailer")}function reloadFromItem(instance,page,params,item,user){var context=params.context;renderName(item,page.querySelector(".nameContainer"),!1,context);var apiClient=connectionManager.getApiClient(item.ServerId);renderSeriesTimerEditor(page,item,apiClient,user),renderTimerEditor(page,item,apiClient,user),renderImage(page,item,apiClient,user),renderLogo(page,item,apiClient),setTitle(item,apiClient),setInitialCollapsibleState(page,item,apiClient,context,user),renderDetails(page,item,apiClient,context),renderTrackSelections(page,instance,item),dom.getWindowSize().innerWidth>=1e3?backdrop.setBackdrops([item]):backdrop.clear(),libraryBrowser.renderDetailPageBackdrop(page,item,apiClient,imageLoader,indicators);var canPlay=reloadPlayButtons(page,item);(item.LocalTrailerCount||item.RemoteTrailers&&item.RemoteTrailers.length)&&-1!==playbackManager.getSupportedCommands().indexOf("PlayTrailers")?hideAll(page,"btnPlayTrailer",!0):hideAll(page,"btnPlayTrailer"),setTrailerButtonVisibility(page,item),item.CanDelete&&!item.IsFolder?hideAll(page,"btnDeleteItem",!0):hideAll(page,"btnDeleteItem"),renderSyncLocalContainer(page,params,user,item),"Program"!==item.Type||canPlay?hideAll(page,"mainDetailButtons",!0):hideAll(page,"mainDetailButtons"),showRecordingFields(instance,page,item,user);var groupedVersions=(item.MediaSources||[]).filter(function(g){return"Grouping"==g.Type});user.Policy.IsAdministrator&&groupedVersions.length?page.querySelector(".splitVersionContainer").classList.remove("hide"):page.querySelector(".splitVersionContainer").classList.add("hide"),itemContextMenu.getCommands(getContextMenuOptions(item,user)).length?hideAll(page,"btnMoreCommands",!0):hideAll(page,"btnMoreCommands");var itemBirthday=page.querySelector("#itemBirthday");if("Person"==item.Type&&item.PremiereDate)try{var birthday=datetime.parseISO8601Date(item.PremiereDate,!0).toDateString();itemBirthday.classList.remove("hide"),itemBirthday.innerHTML=globalize.translate("BirthDateValue").replace("{0}",birthday)}catch(err){itemBirthday.classList.add("hide")}else itemBirthday.classList.add("hide");var itemDeathDate=page.querySelector("#itemDeathDate");if("Person"==item.Type&&item.EndDate)try{var deathday=datetime.parseISO8601Date(item.EndDate,!0).toDateString();itemDeathDate.classList.remove("hide"),itemDeathDate.innerHTML=globalize.translate("DeathDateValue").replace("{0}",deathday)}catch(err){itemDeathDate.classList.add("hide")}var itemBirthLocation=page.querySelector("#itemBirthLocation");if("Person"==item.Type&&item.ProductionLocations&&item.ProductionLocations.length){var gmap=''+item.ProductionLocations[0]+" ";itemBirthLocation.classList.remove("hide"),itemBirthLocation.innerHTML=globalize.translate("BirthPlaceValue").replace("{0}",gmap)}else itemBirthLocation.classList.add("hide");setPeopleHeader(page,item),loading.hide()}function logoImageUrl(item,apiClient,options){return options=options||{},options.type="Logo",item.ImageTags&&item.ImageTags.Logo?(options.tag=item.ImageTags.Logo,apiClient.getScaledImageUrl(item.Id,options)):item.ParentLogoImageTag?(options.tag=item.ParentLogoImageTag,apiClient.getScaledImageUrl(item.ParentLogoItemId,options)):null}function setTitle(item,apiClient){var url=logoImageUrl(item,apiClient,{});if(url=null){var pageTitle=document.querySelector(".pageTitle");pageTitle.style.backgroundImage="url('"+url+"')",pageTitle.classList.add("pageTitleWithLogo"),pageTitle.innerHTML=""}else Emby.Page.setTitle("")}function renderLogo(page,item,apiClient){var url=logoImageUrl(item,apiClient,{maxWidth:300}),detailLogo=page.querySelector(".detailLogo");url?(detailLogo.classList.remove("hide"),detailLogo.classList.add("lazy"),detailLogo.setAttribute("data-src",url),imageLoader.lazyImage(detailLogo)):detailLogo.classList.add("hide")}function showRecordingFields(instance,page,item,user){if(!instance.currentRecordingFields){var recordingFieldsElement=page.querySelector(".recordingFields");"Program"==item.Type&&user.Policy.EnableLiveTvManagement?require(["recordingFields"],function(recordingFields){instance.currentRecordingFields=new recordingFields({parent:recordingFieldsElement,programId:item.Id,serverId:item.ServerId}),recordingFieldsElement.classList.remove("hide")}):(recordingFieldsElement.classList.add("hide"),recordingFieldsElement.innerHTML="")}}function renderLinks(linksElem,item){var html=[];if(item.DateCreated&&itemHelper.enableDateAddedDisplay(item)){var dateCreated=datetime.parseISO8601Date(item.DateCreated);html.push(globalize.translate("sharedcomponents#AddedOnValue",datetime.toLocaleDateString(dateCreated)+" "+datetime.getDisplayTime(dateCreated)))}var links=[];if(!layoutManager.tv&&(item.HomePageUrl&&links.push(''+globalize.translate("ButtonWebsite")+" "),item.ExternalUrls))for(var i=0,length=item.ExternalUrls.length;i'+url.Name+"")}links.length&&html.push(globalize.translate("sharedcomponents#LinksValue",links.join(", "))),linksElem.innerHTML=html.join(", "),html.length?linksElem.classList.remove("hide"):linksElem.classList.add("hide")}function renderImage(page,item,apiClient,user){var container=page.querySelector(".detailImageContainer");libraryBrowser.renderDetailImage(page,container,item,apiClient,user.Policy.IsAdministrator&&"Photo"!=item.MediaType,imageLoader,indicators)}function refreshDetailImageUserData(elem,item){elem.querySelector(".detailImageProgressContainer").innerHTML=indicators.getProgressBarHtml(item)}function refreshImage(page,item,user){refreshDetailImageUserData(page.querySelector(".detailImageContainer"),item)}function setPeopleHeader(page,item){"Audio"==item.MediaType||"MusicAlbum"==item.Type||"Book"==item.MediaType||"Photo"==item.MediaType?page.querySelector("#peopleHeader").innerHTML=globalize.translate("HeaderPeople"):page.querySelector("#peopleHeader").innerHTML=globalize.translate("HeaderCastAndCrew")}function renderNextUp(page,item,user){var section=page.querySelector(".nextUpSection");if("Series"!=item.Type)return void section.classList.add("hide");connectionManager.getApiClient(item.ServerId).getNextUpEpisodes({SeriesId:item.Id,UserId:user.Id}).then(function(result){result.Items.length?section.classList.remove("hide"):section.classList.add("hide");var html=cardBuilder.getCardsHtml({items:result.Items,shape:getThumbShape(!1),showTitle:!0,displayAsSpecial:"Season"==item.Type&&item.IndexNumber,overlayText:!1,centerText:!0,overlayPlayButton:!0}),itemsContainer=section.querySelector(".nextUpItems");itemsContainer.innerHTML=html,imageLoader.lazyChildren(itemsContainer)})}function setInitialCollapsibleState(page,item,apiClient,context,user){page.querySelector(".collectionItems").innerHTML="","Playlist"==item.Type?(page.querySelector("#childrenCollapsible").classList.remove("hide"),renderPlaylistItems(page,item,user)):"Studio"==item.Type||"Person"==item.Type||"Genre"==item.Type||"MusicGenre"==item.Type||"GameGenre"==item.Type||"MusicArtist"==item.Type?(page.querySelector("#childrenCollapsible").classList.remove("hide"),renderItemsByName(page,item,user)):item.IsFolder?("BoxSet"==item.Type&&page.querySelector("#childrenCollapsible").classList.add("hide"),renderChildren(page,item)):page.querySelector("#childrenCollapsible").classList.add("hide"),item.Type,"Series"==item.Type?renderNextUp(page,item,user):page.querySelector(".nextUpSection").classList.add("hide"),item.MediaSources&&item.MediaSources.length&&(null==item.EnableMediaSourceDisplay?"Channel"!==item.SourceType:item.EnableMediaSourceDisplay)?renderMediaSources(page,user,item):page.querySelector(".audioVideoMediaInfo").classList.add("hide"),renderScenes(page,item),item.SpecialFeatureCount&&0!=item.SpecialFeatureCount&&"Series"!=item.Type?(page.querySelector("#specialsCollapsible").classList.remove("hide"),renderSpecials(page,item,user,6)):page.querySelector("#specialsCollapsible").classList.add("hide"),renderCast(page,item,context,enableScrollX()?null:12),item.PartCount&&item.PartCount>1?(page.querySelector("#additionalPartsCollapsible").classList.remove("hide"),renderAdditionalParts(page,item,user)):page.querySelector("#additionalPartsCollapsible").classList.add("hide"),page.querySelector("#themeSongsCollapsible").classList.add("hide"),page.querySelector("#themeVideosCollapsible").classList.add("hide"),"MusicAlbum"==item.Type?renderMusicVideos(page,item,user):page.querySelector("#musicVideosCollapsible").classList.add("hide"),renderThemeMedia(page,item)}function renderOverview(elems,item){for(var i=0,length=elems.length;i'+p.Name+""}).join(", "),elem=page.querySelector(".genres");elem.innerHTML=genres.length>1?globalize.translate("sharedcomponents#GenresValue",html):globalize.translate("sharedcomponents#GenreValue",html),genres.length?elem.classList.remove("hide"):elem.classList.add("hide")}function renderDirector(page,item,apiClient,context,isStatic){var directors=(item.People||[]).filter(function(p){return"Director"===p.Type}),html=directors.map(function(p){return''+p.Name+" "}).join(", "),elem=page.querySelector(".directors");elem.innerHTML=directors.length>1?globalize.translate("sharedcomponents#DirectorsValue",html):globalize.translate("sharedcomponents#DirectorValue",html),directors.length?elem.classList.remove("hide"):elem.classList.add("hide")}function renderDetails(page,item,apiClient,context,isStatic){renderSimilarItems(page,item,context),renderMoreFromSeason(page,item,apiClient),renderMoreFromArtist(page,item,apiClient),renderDirector(page,item,apiClient,context,isStatic),renderGenres(page,item,apiClient,context,isStatic),renderChannelGuide(page,apiClient,item);var taglineElement=page.querySelector(".tagline");item.Taglines&&item.Taglines.length?(taglineElement.classList.remove("hide"),taglineElement.innerHTML=item.Taglines[0]):taglineElement.classList.add("hide");var overview=page.querySelector(".overview"),externalLinksElem=page.querySelector(".itemExternalLinks");"Season"!==item.Type&&"MusicAlbum"!==item.Type&&"MusicArtist"!==item.Type||(overview.classList.add("detailsHiddenOnMobile"),externalLinksElem.classList.add("detailsHiddenOnMobile")),renderOverview([overview],item);var i,length,itemMiscInfo=page.querySelectorAll(".itemMiscInfo-primary");for(i=0,length=itemMiscInfo.length;i "),page.querySelector(".photoInfoContent").innerHTML=html}function enableScrollX(){return browserInfo.mobile&&screen.availWidth<=1e3}function getPortraitShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowPortrait":"portrait"}function getSquareShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowSquare":"square"}function getThumbShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowBackdrop":"backdrop"}function renderMoreFromSeason(view,item,apiClient){var section=view.querySelector(".moreFromSeasonSection");if(section){if("Episode"!==item.Type||!item.SeasonId||!item.SeriesId)return void section.classList.add("hide");var userId=apiClient.getCurrentUserId();apiClient.getEpisodes(item.SeriesId,{SeasonId:item.SeasonId,UserId:userId,Fields:"ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete"}).then(function(result){if(result.Items.length<2)return void section.classList.add("hide");section.classList.remove("hide"),section.querySelector("h2").innerHTML=globalize.translate("MoreFromValue",item.SeasonName);var itemsContainer=section.querySelector(".itemsContainer");cardBuilder.buildCards(result.Items,{parentContainer:section,itemsContainer:itemsContainer,shape:"autoVertical",sectionTitleTagName:"h2",scalable:!0,showTitle:!0,overlayText:!1,centerText:!0,includeParentInfoInTitle:!1,allowBottomPadding:!1});var card=itemsContainer.querySelector('.card[data-id="'+item.Id+'"]');card&&setTimeout(function(){section.querySelector(".emby-scroller").toStart(card.previousSibling||card,!0)},100)})}}function renderMoreFromArtist(view,item,apiClient){var section=view.querySelector(".moreFromArtistSection");if(section)return"MusicAlbum"===item.Type&&item.AlbumArtists&&item.AlbumArtists.length?void apiClient.getItems(apiClient.getCurrentUserId(),{IncludeItemTypes:"MusicAlbum",ArtistIds:item.AlbumArtists[0].Id,Recursive:!0,ExcludeItemIds:item.Id,SortBy:"ProductionYear,SortName",SortOrder:"Descending"}).then(function(result){if(!result.Items.length)return void section.classList.add("hide");section.classList.remove("hide"),section.querySelector("h2").innerHTML=globalize.translate("MoreFromValue",item.AlbumArtists[0].Name),cardBuilder.buildCards(result.Items,{parentContainer:section,itemsContainer:section.querySelector(".itemsContainer"),shape:"autoVertical",sectionTitleTagName:"h2",scalable:!0,coverImage:"MusicArtist"===item.Type||"MusicAlbum"===item.Type,showTitle:!0,showParentTitle:!1,centerText:!0,overlayText:!1,overlayPlayButton:!0})}):void section.classList.add("hide")}function renderSimilarItems(page,item,context){var similarCollapsible=page.querySelector("#similarCollapsible");if(similarCollapsible){if("Movie"!=item.Type&&"Trailer"!=item.Type&&"Series"!=item.Type&&"Program"!=item.Type&&"Recording"!=item.Type&&"Game"!=item.Type&&"MusicAlbum"!=item.Type&&"MusicArtist"!=item.Type&&"ChannelVideoItem"!=item.Type)return void similarCollapsible.classList.add("hide");similarCollapsible.classList.remove("hide");var shape="MusicAlbum"==item.Type||"MusicArtist"==item.Type?"square":"portrait",apiClient=connectionManager.getApiClient(item.ServerId),options={userId:apiClient.getCurrentUserId(),limit:"MusicAlbum"==item.Type||"MusicArtist"==item.Type?8:10,fields:"PrimaryImageAspectRatio,UserData,CanDelete"};"MusicAlbum"==item.Type&&item.AlbumArtists&&item.AlbumArtists.length&&(options.ExcludeArtistIds=item.AlbumArtists[0].Id),apiClient.getSimilarItems(item.Id,options).then(function(result){if(!result.Items.length)return void similarCollapsible.classList.add("hide");similarCollapsible.classList.remove("hide");var html="";html+='';var supportsImageAnalysis=appHost.supports("imageanalysis"),cardLayout=supportsImageAnalysis&&("MusicAlbum"==item.Type||"Game"==item.Type||"MusicArtist"==item.Type);cardLayout=!1,html+=cardBuilder.getCardsHtml({items:result.Items,shape:shape,showParentTitle:"MusicAlbum"==item.Type,centerText:!cardLayout,showTitle:"MusicAlbum"==item.Type||"Game"==item.Type||"MusicArtist"==item.Type,context:context,lazy:!0,showDetailsMenu:!0,coverImage:"MusicAlbum"==item.Type||"MusicArtist"==item.Type,overlayPlayButton:!0,cardLayout:cardLayout,vibrant:cardLayout&&supportsImageAnalysis}),html+="
";var similarContent=similarCollapsible.querySelector(".similarContent");similarContent.innerHTML=html,imageLoader.lazyChildren(similarContent)})}}function renderSeriesAirTime(page,item,isStatic){var seriesAirTime=page.querySelector("#seriesAirTime");if("Series"!=item.Type)return void seriesAirTime.classList.add("hide");var html="";if(item.AirDays&&item.AirDays.length&&(html+=7==item.AirDays.length?"daily":item.AirDays.map(function(a){return a+"s"}).join(",")),item.AirTime&&(html+=" at "+item.AirTime),item.Studios.length)if(isStatic)html+=" on "+item.Studios[0].Name;else{
-var context=inferContext(item),href=appRouter.getRouteUrl(item.Studios[0],{context:context,itemType:"Studio",serverId:item.ServerId});html+=' on '+item.Studios[0].Name+" "}html?(html=("Ended"==item.Status?"Aired ":"Airs ")+html,seriesAirTime.innerHTML=html,seriesAirTime.classList.remove("hide")):seriesAirTime.classList.add("hide")}function renderTags(page,item){var itemTags=page.querySelector(".itemTags"),tagElements=[],tags=item.Tags||[];"Program"===item.Type&&(tags=[]);for(var i=0,length=tags.length;i',html+=''+datetime.toLocaleDateString(currentStartDate,{weekday:"long",month:"long",day:"numeric"})+" ",html+=''+listView.getListViewHtml({items:currentItems,enableUserDataButtons:!1,showParentTitle:!0,image:!1,showProgramTime:!0,mediaInfo:!1,parentTitleWithTitle:!0})+"
"),currentStartDate=itemStartDate,currentItems=[]),currentItems.push(item)}currentItems.length&&(html+='',html+='
'+datetime.toLocaleDateString(currentStartDate,{weekday:"long",month:"long",day:"numeric"})+" ",html+='
'+listView.getListViewHtml({items:currentItems,enableUserDataButtons:!1,showParentTitle:!0,image:!1,showProgramTime:!0,mediaInfo:!1,parentTitleWithTitle:!0})+"
"),page.querySelector(".programGuide").innerHTML=html}function renderChannelGuide(page,apiClient,item){"TvChannel"===item.Type&&(page.querySelector(".programGuideSection").classList.remove("hide"),apiClient.getLiveTvPrograms({ChannelIds:item.Id,UserId:apiClient.getCurrentUserId(),HasAired:!1,SortBy:"StartDate",EnableTotalRecordCount:!1,EnableImages:!1,ImageTypeLimit:0,EnableUserData:!1}).then(function(result){renderProgramsForChannel(page,result)}))}function inferContext(item){return"Movie"===item.Type||"BoxSet"===item.Type?"movies":"Series"===item.Type||"Season"===item.Type||"Episode"===item.Type?"tvshows":"Game"===item.Type||"GameSystem"===item.Type?"games":"Game"===item.Type||"GameSystem"===item.Type?"games":"MusicArtist"===item.Type||"MusicAlbum"===item.Type?"music":"Program"===item.Type?"livetv":null}function filterItemsByCollectionItemType(items,typeInfo){return items.filter(function(item){return typeInfo.mediaType?item.MediaType==typeInfo.mediaType:item.Type==typeInfo.type})}function renderCollectionItems(page,parentItem,types,items){page.querySelector(".collectionItems").innerHTML="";var i,length;for(i=0,length=types.length;i0}).length});otherTypeItems.length&&renderCollectionItemType(page,parentItem,otherType,otherTypeItems),items.length||renderCollectionItemType(page,parentItem,{name:globalize.translate("HeaderItems")},items);var containers=page.querySelectorAll(".collectionItemsContainer"),notifyRefreshNeeded=function(){renderChildren(page,parentItem)};for(i=0,length=containers.length;i',html+='',html+='
',html+=""+type.name+" ",html+=" ",html+=' ',html+="",html+='';var shape="MusicAlbum"==type.type?getSquareShape(!1):getPortraitShape(!1);html+=cardBuilder.getCardsHtml({items:items,shape:shape,showTitle:!0,centerText:!0,lazy:!0,showDetailsMenu:!0,overlayMoreButton:!0,showAddToCollection:!1,showRemoveFromCollection:!0,collectionId:parentItem.Id}),html+="
",html+="";var collectionItems=page.querySelector(".collectionItems");collectionItems.insertAdjacentHTML("beforeend",html),imageLoader.lazyChildren(collectionItems),collectionItems.querySelector(".btnAddToCollection").addEventListener("click",function(){require(["alert"],function(alert){alert({text:globalize.translate("AddItemToCollectionHelp"),html:globalize.translate("AddItemToCollectionHelp")+''+globalize.translate("ButtonLearnMore")+" "})})})}function renderThemeMedia(page,item){if("SeriesTimer"!==item.Type&&"Timer"!==item.Type&&"Genre"!==item.Type&&"MusicGenre"!==item.Type&&"GameGenre"!==item.Type&&"Studio"!==item.Type&&"Person"!==item.Type){var apiClient=connectionManager.getApiClient(item.ServerId);apiClient.getThemeMedia(apiClient.getCurrentUserId(),item.Id,!0).then(function(result){var themeSongs=result.ThemeSongsResult.OwnerId==item.Id?result.ThemeSongsResult.Items:[],themeVideos=result.ThemeVideosResult.OwnerId==item.Id?result.ThemeVideosResult.Items:[];renderThemeSongs(page,themeSongs),renderThemeVideos(page,themeVideos)})}}function renderThemeSongs(page,items){if(items.length){page.querySelector("#themeSongsCollapsible").classList.remove("hide");var html=listView.getListViewHtml({items:items});page.querySelector("#themeSongsContent").innerHTML=html}else page.querySelector("#themeSongsCollapsible").classList.add("hide")}function renderThemeVideos(page,items,user){if(items.length){page.querySelector("#themeVideosCollapsible").classList.remove("hide");var themeVideosContent=page.querySelector("#themeVideosContent");themeVideosContent.innerHTML=getVideosHtml(items,user),imageLoader.lazyChildren(themeVideosContent)}else page.querySelector("#themeVideosCollapsible").classList.add("hide")}function renderMusicVideos(page,item,user){connectionManager.getApiClient(item.ServerId).getItems(user.Id,{SortBy:"SortName",SortOrder:"Ascending",IncludeItemTypes:"MusicVideo",Recursive:!0,Fields:"DateCreated,CanDelete",AlbumIds:item.Id}).then(function(result){if(result.Items.length){page.querySelector("#musicVideosCollapsible").classList.remove("hide");var musicVideosContent=page.querySelector(".musicVideosContent");musicVideosContent.innerHTML=getVideosHtml(result.Items,user),imageLoader.lazyChildren(musicVideosContent)}else page.querySelector("#musicVideosCollapsible").classList.add("hide")})}function renderAdditionalParts(page,item,user){connectionManager.getApiClient(item.ServerId).getAdditionalVideoParts(user.Id,item.Id).then(function(result){if(result.Items.length){page.querySelector("#additionalPartsCollapsible").classList.remove("hide");var additionalPartsContent=page.querySelector("#additionalPartsContent");additionalPartsContent.innerHTML=getVideosHtml(result.Items,user),imageLoader.lazyChildren(additionalPartsContent)}else page.querySelector("#additionalPartsCollapsible").classList.add("hide")})}function renderScenes(page,item){var chapters=item.Chapters||[];if(chapters.length&&!chapters[0].ImageTag&&(chapters=[]),chapters.length){page.querySelector("#scenesCollapsible").classList.remove("hide");var scenesContent=page.querySelector("#scenesContent");enableScrollX()?scenesContent.classList.add("scrollX"):scenesContent.classList.add("vertical-wrap"),require(["chaptercardbuilder"],function(chaptercardbuilder){chaptercardbuilder.buildChapterCards(item,chapters,{itemsContainer:scenesContent,width:400,backdropShape:getThumbShape(),squareShape:getSquareShape()})})}else page.querySelector("#scenesCollapsible").classList.add("hide")}function renderMediaSources(page,user,item){var html=item.MediaSources.map(function(v){return getMediaSourceHtml(user,item,v)}).join('
');item.MediaSources.length>1&&(html=" "+html),page.querySelector("#mediaInfoContent").innerHTML=html,html?page.querySelector(".audioVideoMediaInfo").classList.remove("hide"):page.querySelector(".audioVideoMediaInfo").classList.add("hide")}function getMediaSourceHtml(user,item,version){var html="";version.Name&&item.MediaSources.length>1&&(html+=''+version.Name+"
");for(var i=0,length=version.MediaStreams.length;i';html+='";var attributes=[];stream.DisplayTitle&&attributes.push(createAttribute("Title",stream.DisplayTitle)),stream.Language&&"Video"!=stream.Type&&attributes.push(createAttribute(globalize.translate("MediaInfoLanguage"),stream.Language)),stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoCodec"),stream.Codec.toUpperCase())),stream.CodecTag&&attributes.push(createAttribute(globalize.translate("MediaInfoCodecTag"),stream.CodecTag)),null!=stream.IsAVC&&attributes.push(createAttribute("AVC",stream.IsAVC?"Yes":"No")),stream.Profile&&attributes.push(createAttribute(globalize.translate("MediaInfoProfile"),stream.Profile)),stream.Level&&attributes.push(createAttribute(globalize.translate("MediaInfoLevel"),stream.Level)),(stream.Width||stream.Height)&&attributes.push(createAttribute(globalize.translate("MediaInfoResolution"),stream.Width+"x"+stream.Height)),stream.AspectRatio&&"mjpeg"!=stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoAspectRatio"),stream.AspectRatio)),"Video"==stream.Type&&(null!=stream.IsAnamorphic&&attributes.push(createAttribute(globalize.translate("MediaInfoAnamorphic"),stream.IsAnamorphic?"Yes":"No")),attributes.push(createAttribute(globalize.translate("MediaInfoInterlaced"),stream.IsInterlaced?"Yes":"No"))),(stream.AverageFrameRate||stream.RealFrameRate)&&attributes.push(createAttribute(globalize.translate("MediaInfoFramerate"),stream.AverageFrameRate||stream.RealFrameRate)),stream.ChannelLayout&&attributes.push(createAttribute(globalize.translate("MediaInfoLayout"),stream.ChannelLayout)),stream.Channels&&attributes.push(createAttribute(globalize.translate("MediaInfoChannels"),stream.Channels+" ch")),stream.BitRate&&"mjpeg"!=stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoBitrate"),parseInt(stream.BitRate/1e3)+" kbps")),stream.SampleRate&&attributes.push(createAttribute(globalize.translate("MediaInfoSampleRate"),stream.SampleRate+" Hz")),stream.VideoRange&&"SDR"!==stream.VideoRange&&attributes.push(createAttribute(globalize.translate("sharedcomponents#VideoRange"),stream.VideoRange)),stream.ColorPrimaries&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorPrimaries"),stream.ColorPrimaries)),stream.ColorSpace&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorSpace"),stream.ColorSpace)),stream.ColorTransfer&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorTransfer"),stream.ColorTransfer)),stream.BitDepth&&attributes.push(createAttribute(globalize.translate("MediaInfoBitDepth"),stream.BitDepth+" bit")),stream.PixelFormat&&attributes.push(createAttribute(globalize.translate("MediaInfoPixelFormat"),stream.PixelFormat)),stream.RefFrames&&attributes.push(createAttribute(globalize.translate("MediaInfoRefFrames"),stream.RefFrames)),stream.NalLengthSize&&attributes.push(createAttribute("NAL",stream.NalLengthSize)),"Video"!=stream.Type&&attributes.push(createAttribute(globalize.translate("MediaInfoDefault"),stream.IsDefault?"Yes":"No")),"Subtitle"==stream.Type&&(attributes.push(createAttribute(globalize.translate("MediaInfoForced"),stream.IsForced?"Yes":"No")),attributes.push(createAttribute(globalize.translate("MediaInfoExternal"),stream.IsExternal?"Yes":"No"))),"Video"==stream.Type&&version.Timestamp&&attributes.push(createAttribute(globalize.translate("MediaInfoTimestamp"),version.Timestamp)),html+=attributes.join(" "),html+=""}}if(version.Container&&(html+=''+globalize.translate("MediaInfoContainer")+' '+version.Container+"
"),version.Formats&&version.Formats.length,version.Path&&"Http"!=version.Protocol&&user&&user.Policy.IsAdministrator&&(html+=''+globalize.translate("MediaInfoPath")+' '+version.Path+"
"),version.Size){var size=(version.Size/1048576).toFixed(0);html+=''+globalize.translate("MediaInfoSize")+' '+size+" MB
"}return html}function createAttribute(label,value){return''+label+' '+value+" "}function getVideosHtml(items,user,limit,moreButtonClass){var html=cardBuilder.getCardsHtml({items:items,shape:"auto",showTitle:!0,action:"play",overlayText:!1,centerText:!0,showRuntime:!0});return limit&&items.length>limit&&(html+=''+globalize.translate("ButtonMore")+"
"),html}function renderSpecials(page,item,user,limit){connectionManager.getApiClient(item.ServerId).getSpecialFeatures(user.Id,item.Id).then(function(specials){var specialsContent=page.querySelector("#specialsContent");specialsContent.innerHTML=getVideosHtml(specials,user,limit,"moreSpecials"),imageLoader.lazyChildren(specialsContent)})}function renderCast(page,item,context,limit,isStatic){var people=(item.People||[]).filter(function(p){return"Director"!==p.Type});if(!people.length)return void page.querySelector("#castCollapsible").classList.add("hide");page.querySelector("#castCollapsible").classList.remove("hide");var castContent=page.querySelector("#castContent");enableScrollX()?(castContent.classList.add("scrollX"),limit=32):castContent.classList.add("vertical-wrap");var limitExceeded=limit&&people.length>limit;limitExceeded&&(people=people.slice(0),people.length=Math.min(limit,people.length)),require(["peoplecardbuilder"],function(peoplecardbuilder){peoplecardbuilder.buildPeopleCards(people,{itemsContainer:castContent,coverImage:!0,serverId:item.ServerId,width:160,shape:getPortraitShape()})});var morePeopleButton=page.querySelector(".morePeople");morePeopleButton&&(limitExceeded&&!enableScrollX()?morePeopleButton.classList.remove("hide"):morePeopleButton.classList.add("hide"))}function itemDetailPage(){var self=this;self.setInitialCollapsibleState=setInitialCollapsibleState,self.renderDetails=renderDetails,self.renderCast=renderCast,self.renderMediaSources=renderMediaSources}function bindAll(view,selector,eventName,fn){var i,length,elems=view.querySelectorAll(selector);for(i=0,length=elems.length;i',html+=listView.getListViewHtml({items:items,enableUserDataButtons:!1,image:!0,imageSource:"channel",showProgramDateTime:!0,showChannel:!1,mediaInfo:!1,action:"none",moreButton:!1,recordButton:!1}),html+=""}function renderSeriesTimerSchedule(page,apiClient,seriesTimerId){apiClient.getLiveTvTimers({UserId:apiClient.getCurrentUserId(),ImageTypeLimit:1,EnableImageTypes:"Primary,Backdrop,Thumb",SortBy:"StartDate",EnableTotalRecordCount:!1,EnableUserData:!1,SeriesTimerId:seriesTimerId,Fields:"ChannelInfo,ChannelImage"}).then(function(result){result.Items.length&&result.Items[0].SeriesTimerId!=seriesTimerId&&(result.Items=[]);var html=getProgramScheduleHtml(result.Items),scheduleTab=page.querySelector(".seriesTimerSchedule");scheduleTab.innerHTML=html,imageLoader.lazyChildren(scheduleTab)})}function renderTimerEditor(page,item,apiClient,user){if("Recording"!==item.Type||!user.Policy.EnableLiveTvManagement||!item.TimerId||"InProgress"!==item.Status)return void hideAll(page,"btnCancelTimer");hideAll(page,"btnCancelTimer",!0)}function renderSeriesTimerEditor(page,item,apiClient,user){return"SeriesTimer"!==item.Type?void hideAll(page,"btnCancelSeriesTimer"):user.Policy.EnableLiveTvManagement?(require(["seriesRecordingEditor"],function(seriesRecordingEditor){seriesRecordingEditor.embed(item,apiClient.serverId(),{context:page.querySelector(".seriesRecordingEditor")})}),page.querySelector(".seriesTimerScheduleSection").classList.remove("hide"),hideAll(page,"btnCancelSeriesTimer",!0),void renderSeriesTimerSchedule(page,apiClient,item.Id)):(page.querySelector(".seriesTimerScheduleSection").classList.add("hide"),void hideAll(page,"btnCancelSeriesTimer"))}function renderTrackSelections(page,instance,item){var select=page.querySelector(".selectSource");if(!item.MediaSources||!itemHelper.supportsMediaSourceSelection(item)||-1===playbackManager.getSupportedCommands().indexOf("PlayMediaSource")||!playbackManager.canPlay(item))return page.querySelector(".trackSelections").classList.add("hide"),select.innerHTML="",page.querySelector(".selectVideo").innerHTML="",page.querySelector(".selectAudio").innerHTML="",void(page.querySelector(".selectSubtitles").innerHTML="");playbackManager.getPlaybackMediaSources(item).then(function(mediaSources){instance._currentPlaybackMediaSources=mediaSources,page.querySelector(".trackSelections").classList.remove("hide"),select.setLabel(globalize.translate("sharedcomponents#LabelVersion"));var currentValue=select.value,selectedId=mediaSources[0].Id;select.innerHTML=mediaSources.map(function(v){var selected=v.Id===selectedId?" selected":"";return'"+v.Name+" "}).join(""),mediaSources.length>1?page.querySelector(".selectSourceContainer").classList.remove("hide"):page.querySelector(".selectSourceContainer").classList.add("hide"),select.value!==currentValue&&(renderVideoSelections(page,mediaSources),renderAudioSelections(page,mediaSources),renderSubtitleSelections(page,mediaSources))})}function renderVideoSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Video"===m.Type}),select=page.querySelector(".selectVideo");select.setLabel(globalize.translate("sharedcomponents#LabelVideo"));var selectedId=tracks.length?tracks[0].Index:-1;select.innerHTML=tracks.map(function(v){var selected=v.Index===selectedId?" selected":"",titleParts=[],resolutionText=mediaInfo.getResolutionText(v);return resolutionText&&titleParts.push(resolutionText),v.Codec&&titleParts.push(v.Codec.toUpperCase()),'"+(v.DisplayTitle||titleParts.join(" "))+" "}).join(""),select.setAttribute("disabled","disabled"),tracks.length?page.querySelector(".selectVideoContainer").classList.remove("hide"):page.querySelector(".selectVideoContainer").classList.add("hide")}function renderAudioSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Audio"===m.Type}),select=page.querySelector(".selectAudio");select.setLabel(globalize.translate("sharedcomponents#LabelAudio"));var selectedId=mediaSource.DefaultAudioStreamIndex;select.innerHTML=tracks.map(function(v){var selected=v.Index===selectedId?" selected":"";return'"+v.DisplayTitle+" "}).join(""),tracks.length>1?select.removeAttribute("disabled"):select.setAttribute("disabled","disabled"),tracks.length?page.querySelector(".selectAudioContainer").classList.remove("hide"):page.querySelector(".selectAudioContainer").classList.add("hide")}function renderSubtitleSelections(page,mediaSources){var mediaSourceId=page.querySelector(".selectSource").value,mediaSource=mediaSources.filter(function(m){return m.Id===mediaSourceId})[0],tracks=mediaSource.MediaStreams.filter(function(m){return"Subtitle"===m.Type}),select=page.querySelector(".selectSubtitles");select.setLabel(globalize.translate("sharedcomponents#LabelSubtitles"));var selectedId=null==mediaSource.DefaultSubtitleStreamIndex?-1:mediaSource.DefaultSubtitleStreamIndex;if(tracks.length){var selected=-1===selectedId?" selected":"";select.innerHTML=''+globalize.translate("sharedcomponents#Off")+" "+tracks.map(function(v){return selected=v.Index===selectedId?" selected":"",'"+v.DisplayTitle+" "}).join(""),page.querySelector(".selectSubtitlesContainer").classList.remove("hide")}else select.innerHTML="",page.querySelector(".selectSubtitlesContainer").classList.add("hide")}function reloadPlayButtons(page,item){var canPlay=!1;if("Program"==item.Type){var now=new Date;now>=datetime.parseISO8601Date(item.StartDate,!0)&&now0)}else hideAll(page,"btnPlay"),hideAll(page,"btnResume"),hideAll(page,"btnInstantMix"),hideAll(page,"btnShuffle");return canPlay}function reloadUserDataButtons(page,item){var i,length,btnPlaystates=page.querySelectorAll(".btnPlaystate");for(i=0,length=btnPlaystates.length;i'+artist.Name+"")}return html=html.join(" / ")}function renderName(item,container,isStatic,context){var parentRoute,parentNameHtml=[],parentNameLast=!1;item.AlbumArtists?(parentNameHtml.push(getArtistLinksHtml(item.AlbumArtists,item.ServerId,context)),parentNameLast=!0):item.ArtistItems&&item.ArtistItems.length&&"MusicVideo"===item.Type?(parentNameHtml.push(getArtistLinksHtml(item.ArtistItems,item.ServerId,context)),parentNameLast=!0):item.SeriesName&&"Episode"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeriesId,Name:item.SeriesName,Type:"Series",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeriesName+" ")):(item.IsSeries||item.EpisodeTitle)&&parentNameHtml.push(item.Name),item.SeriesName&&"Season"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeriesId,Name:item.SeriesName,Type:"Series",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeriesName+" ")):null!=item.ParentIndexNumber&&"Episode"===item.Type?(parentRoute=appRouter.getRouteUrl({Id:item.SeasonId,Name:item.SeasonName,Type:"Season",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.SeasonName+" ")):null!=item.ParentIndexNumber&&item.IsSeries?parentNameHtml.push(item.SeasonName||"S"+item.ParentIndexNumber):item.Album&&"Audio"===item.Type&&(item.AlbumId||item.ParentId)?(parentRoute=appRouter.getRouteUrl({Id:item.AlbumId||item.ParentId,Name:item.Album,Type:"MusicAlbum",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.Album+" ")):item.Album&&"MusicVideo"===item.Type&&item.AlbumId?(parentRoute=appRouter.getRouteUrl({Id:item.Albumid,Name:item.Album,Type:"MusicAlbum",IsFolder:!0,ServerId:item.ServerId},{context:context}),parentNameHtml.push(''+item.Album+" ")):item.Album&&parentNameHtml.push(item.Album);var html="";parentNameHtml.length&&(html=parentNameLast?''+parentNameHtml.join(" - ")+" ":''+parentNameHtml.join(" - ")+" ");var name=itemHelper.getDisplayName(item,{includeParentInfo:!1});html&&!parentNameLast?html+=''+name+" ":html=parentNameLast?''+name+" "+html:''+name+" "+html,container.innerHTML=html,html.length?container.classList.remove("hide"):container.classList.add("hide")}function setTrailerButtonVisibility(page,item){(item.LocalTrailerCount||item.RemoteTrailers&&item.RemoteTrailers.length)&&-1!==playbackManager.getSupportedCommands().indexOf("PlayTrailers")?hideAll(page,"btnPlayTrailer",!0):hideAll(page,"btnPlayTrailer")}function reloadFromItem(instance,page,params,item,user){var context=params.context;renderName(item,page.querySelector(".nameContainer"),!1,context);var apiClient=connectionManager.getApiClient(item.ServerId);renderSeriesTimerEditor(page,item,apiClient,user),renderTimerEditor(page,item,apiClient,user),renderImage(page,item,apiClient,user),renderLogo(page,item,apiClient),setTitle(item,apiClient),setInitialCollapsibleState(page,item,apiClient,context,user),renderDetails(page,item,apiClient,context),renderTrackSelections(page,instance,item),dom.getWindowSize().innerWidth>=1e3?backdrop.setBackdrops([item]):backdrop.clear(),libraryBrowser.renderDetailPageBackdrop(page,item,apiClient,imageLoader,indicators);var canPlay=reloadPlayButtons(page,item);(item.LocalTrailerCount||item.RemoteTrailers&&item.RemoteTrailers.length)&&-1!==playbackManager.getSupportedCommands().indexOf("PlayTrailers")?hideAll(page,"btnPlayTrailer",!0):hideAll(page,"btnPlayTrailer"),setTrailerButtonVisibility(page,item),item.CanDelete&&!item.IsFolder?hideAll(page,"btnDeleteItem",!0):hideAll(page,"btnDeleteItem"),renderSyncLocalContainer(page,params,user,item),"Program"!==item.Type||canPlay?hideAll(page,"mainDetailButtons",!0):hideAll(page,"mainDetailButtons"),showRecordingFields(instance,page,item,user);var groupedVersions=(item.MediaSources||[]).filter(function(g){return"Grouping"==g.Type});user.Policy.IsAdministrator&&groupedVersions.length?page.querySelector(".splitVersionContainer").classList.remove("hide"):page.querySelector(".splitVersionContainer").classList.add("hide"),itemContextMenu.getCommands(getContextMenuOptions(item,user)).length?hideAll(page,"btnMoreCommands",!0):hideAll(page,"btnMoreCommands");var itemBirthday=page.querySelector("#itemBirthday");if("Person"==item.Type&&item.PremiereDate)try{var birthday=datetime.parseISO8601Date(item.PremiereDate,!0).toDateString();itemBirthday.classList.remove("hide"),itemBirthday.innerHTML=globalize.translate("BirthDateValue").replace("{0}",birthday)}catch(err){itemBirthday.classList.add("hide")}else itemBirthday.classList.add("hide");var itemDeathDate=page.querySelector("#itemDeathDate");if("Person"==item.Type&&item.EndDate)try{var deathday=datetime.parseISO8601Date(item.EndDate,!0).toDateString();itemDeathDate.classList.remove("hide"),itemDeathDate.innerHTML=globalize.translate("DeathDateValue").replace("{0}",deathday)}catch(err){itemDeathDate.classList.add("hide")}var itemBirthLocation=page.querySelector("#itemBirthLocation");if("Person"==item.Type&&item.ProductionLocations&&item.ProductionLocations.length){var gmap=''+item.ProductionLocations[0]+" ";itemBirthLocation.classList.remove("hide"),itemBirthLocation.innerHTML=globalize.translate("BirthPlaceValue").replace("{0}",gmap)}else itemBirthLocation.classList.add("hide");setPeopleHeader(page,item),loading.hide()}function logoImageUrl(item,apiClient,options){return options=options||{},options.type="Logo",item.ImageTags&&item.ImageTags.Logo?(options.tag=item.ImageTags.Logo,apiClient.getScaledImageUrl(item.Id,options)):item.ParentLogoImageTag?(options.tag=item.ParentLogoImageTag,apiClient.getScaledImageUrl(item.ParentLogoItemId,options)):null}function setTitle(item,apiClient){var url=logoImageUrl(item,apiClient,{});if(url=null){var pageTitle=document.querySelector(".pageTitle");pageTitle.style.backgroundImage="url('"+url+"')",pageTitle.classList.add("pageTitleWithLogo"),pageTitle.innerHTML=""}else Emby.Page.setTitle("")}function renderLogo(page,item,apiClient){var url=logoImageUrl(item,apiClient,{maxWidth:300}),detailLogo=page.querySelector(".detailLogo");url?(detailLogo.classList.remove("hide"),detailLogo.classList.add("lazy"),detailLogo.setAttribute("data-src",url),imageLoader.lazyImage(detailLogo)):detailLogo.classList.add("hide")}function showRecordingFields(instance,page,item,user){if(!instance.currentRecordingFields){var recordingFieldsElement=page.querySelector(".recordingFields");"Program"==item.Type&&user.Policy.EnableLiveTvManagement?require(["recordingFields"],function(recordingFields){instance.currentRecordingFields=new recordingFields({parent:recordingFieldsElement,programId:item.Id,serverId:item.ServerId}),recordingFieldsElement.classList.remove("hide")}):(recordingFieldsElement.classList.add("hide"),recordingFieldsElement.innerHTML="")}}function renderLinks(linksElem,item){var html=[];if(item.DateCreated&&itemHelper.enableDateAddedDisplay(item)){var dateCreated=datetime.parseISO8601Date(item.DateCreated);html.push(globalize.translate("sharedcomponents#AddedOnValue",datetime.toLocaleDateString(dateCreated)+" "+datetime.getDisplayTime(dateCreated)))}var links=[];if(!layoutManager.tv&&(item.HomePageUrl&&links.push(''+globalize.translate("ButtonWebsite")+" "),item.ExternalUrls))for(var i=0,length=item.ExternalUrls.length;i'+url.Name+"")}links.length&&html.push(globalize.translate("sharedcomponents#LinksValue",links.join(", "))),linksElem.innerHTML=html.join(", "),html.length?linksElem.classList.remove("hide"):linksElem.classList.add("hide")}function renderImage(page,item,apiClient,user){var container=page.querySelector(".detailImageContainer");libraryBrowser.renderDetailImage(page,container,item,apiClient,user.Policy.IsAdministrator&&"Photo"!=item.MediaType,imageLoader,indicators)}function refreshDetailImageUserData(elem,item){elem.querySelector(".detailImageProgressContainer").innerHTML=indicators.getProgressBarHtml(item)}function refreshImage(page,item,user){refreshDetailImageUserData(page.querySelector(".detailImageContainer"),item)}function setPeopleHeader(page,item){"Audio"==item.MediaType||"MusicAlbum"==item.Type||"Book"==item.MediaType||"Photo"==item.MediaType?page.querySelector("#peopleHeader").innerHTML=globalize.translate("HeaderPeople"):page.querySelector("#peopleHeader").innerHTML=globalize.translate("HeaderCastAndCrew")}function renderNextUp(page,item,user){var section=page.querySelector(".nextUpSection");if("Series"!=item.Type)return void section.classList.add("hide");connectionManager.getApiClient(item.ServerId).getNextUpEpisodes({SeriesId:item.Id,UserId:user.Id}).then(function(result){result.Items.length?section.classList.remove("hide"):section.classList.add("hide");var html=cardBuilder.getCardsHtml({items:result.Items,shape:getThumbShape(!1),showTitle:!0,displayAsSpecial:"Season"==item.Type&&item.IndexNumber,overlayText:!1,centerText:!0,overlayPlayButton:!0}),itemsContainer=section.querySelector(".nextUpItems");itemsContainer.innerHTML=html,imageLoader.lazyChildren(itemsContainer)})}function setInitialCollapsibleState(page,item,apiClient,context,user){page.querySelector(".collectionItems").innerHTML="","Playlist"==item.Type?(page.querySelector("#childrenCollapsible").classList.remove("hide"),renderPlaylistItems(page,item,user)):"Studio"==item.Type||"Person"==item.Type||"Genre"==item.Type||"MusicGenre"==item.Type||"GameGenre"==item.Type||"MusicArtist"==item.Type?(page.querySelector("#childrenCollapsible").classList.remove("hide"),renderItemsByName(page,item,user)):item.IsFolder?("BoxSet"==item.Type&&page.querySelector("#childrenCollapsible").classList.add("hide"),renderChildren(page,item)):page.querySelector("#childrenCollapsible").classList.add("hide"),item.Type,"Series"==item.Type?renderNextUp(page,item,user):page.querySelector(".nextUpSection").classList.add("hide"),item.MediaSources&&item.MediaSources.length&&(null==item.EnableMediaSourceDisplay?"Channel"!==item.SourceType:item.EnableMediaSourceDisplay)?renderMediaSources(page,user,item):page.querySelector(".audioVideoMediaInfo").classList.add("hide"),renderScenes(page,item),item.SpecialFeatureCount&&0!=item.SpecialFeatureCount&&"Series"!=item.Type?(page.querySelector("#specialsCollapsible").classList.remove("hide"),renderSpecials(page,item,user,6)):page.querySelector("#specialsCollapsible").classList.add("hide"),renderCast(page,item,context,enableScrollX()?null:12),item.PartCount&&item.PartCount>1?(page.querySelector("#additionalPartsCollapsible").classList.remove("hide"),renderAdditionalParts(page,item,user)):page.querySelector("#additionalPartsCollapsible").classList.add("hide"),page.querySelector("#themeSongsCollapsible").classList.add("hide"),page.querySelector("#themeVideosCollapsible").classList.add("hide"),"MusicAlbum"==item.Type?renderMusicVideos(page,item,user):page.querySelector("#musicVideosCollapsible").classList.add("hide"),renderThemeMedia(page,item)}function renderOverview(elems,item){for(var i=0,length=elems.length;i'+p.Name+""}).join(", "),elem=page.querySelector(".genres");elem.innerHTML=genres.length>1?globalize.translate("sharedcomponents#GenresValue",html):globalize.translate("sharedcomponents#GenreValue",html),genres.length?elem.classList.remove("hide"):elem.classList.add("hide")}function renderDirector(page,item,apiClient,context,isStatic){var directors=(item.People||[]).filter(function(p){return"Director"===p.Type}),html=directors.map(function(p){return''+p.Name+" "}).join(", "),elem=page.querySelector(".directors");elem.innerHTML=directors.length>1?globalize.translate("sharedcomponents#DirectorsValue",html):globalize.translate("sharedcomponents#DirectorValue",html),directors.length?elem.classList.remove("hide"):elem.classList.add("hide")}function renderDetails(page,item,apiClient,context,isStatic){renderSimilarItems(page,item,context),renderMoreFromSeason(page,item,apiClient),renderMoreFromArtist(page,item,apiClient),renderDirector(page,item,apiClient,context,isStatic),renderGenres(page,item,apiClient,context,isStatic),renderChannelGuide(page,apiClient,item);var taglineElement=page.querySelector(".tagline");item.Taglines&&item.Taglines.length?(taglineElement.classList.remove("hide"),taglineElement.innerHTML=item.Taglines[0]):taglineElement.classList.add("hide");var overview=page.querySelector(".overview"),externalLinksElem=page.querySelector(".itemExternalLinks");"Season"!==item.Type&&"MusicAlbum"!==item.Type&&"MusicArtist"!==item.Type||(overview.classList.add("detailsHiddenOnMobile"),externalLinksElem.classList.add("detailsHiddenOnMobile")),renderOverview([overview],item);var i,length,itemMiscInfo=page.querySelectorAll(".itemMiscInfo-primary");for(i=0,length=itemMiscInfo.length;i "),page.querySelector(".photoInfoContent").innerHTML=html}function enableScrollX(){return browserInfo.mobile&&screen.availWidth<=1e3}function getPortraitShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowPortrait":"portrait"}function getSquareShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowSquare":"square"}function getThumbShape(scrollX){return null==scrollX&&(scrollX=enableScrollX()),scrollX?"overflowBackdrop":"backdrop"}function renderMoreFromSeason(view,item,apiClient){var section=view.querySelector(".moreFromSeasonSection");if(section){if("Episode"!==item.Type||!item.SeasonId||!item.SeriesId)return void section.classList.add("hide");var userId=apiClient.getCurrentUserId();apiClient.getEpisodes(item.SeriesId,{SeasonId:item.SeasonId,UserId:userId,Fields:"ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete"}).then(function(result){if(result.Items.length<2)return void section.classList.add("hide");section.classList.remove("hide"),section.querySelector("h2").innerHTML=globalize.translate("MoreFromValue",item.SeasonName);var itemsContainer=section.querySelector(".itemsContainer");cardBuilder.buildCards(result.Items,{parentContainer:section,itemsContainer:itemsContainer,shape:"autoVertical",sectionTitleTagName:"h2",scalable:!0,showTitle:!0,overlayText:!1,centerText:!0,includeParentInfoInTitle:!1,allowBottomPadding:!1});var card=itemsContainer.querySelector('.card[data-id="'+item.Id+'"]');card&&setTimeout(function(){section.querySelector(".emby-scroller").toStart(card.previousSibling||card,!0)},100)})}}function renderMoreFromArtist(view,item,apiClient){var section=view.querySelector(".moreFromArtistSection");if(section){if("MusicAlbum"!==item.Type||!item.AlbumArtists||!item.AlbumArtists.length)return void section.classList.add("hide");var query={IncludeItemTypes:"MusicAlbum",Recursive:!0,ExcludeItemIds:item.Id,SortBy:"ProductionYear,SortName",SortOrder:"Descending"};apiClient.isMinServerVersion("3.4.1.18")?query.AlbumArtistIds=item.AlbumArtists[0].Id:query.ArtistIds=item.AlbumArtists[0].Id,apiClient.getItems(apiClient.getCurrentUserId(),query).then(function(result){if(!result.Items.length)return void section.classList.add("hide");section.classList.remove("hide"),section.querySelector("h2").innerHTML=globalize.translate("MoreFromValue",item.AlbumArtists[0].Name),cardBuilder.buildCards(result.Items,{parentContainer:section,itemsContainer:section.querySelector(".itemsContainer"),shape:"autoVertical",sectionTitleTagName:"h2",scalable:!0,coverImage:"MusicArtist"===item.Type||"MusicAlbum"===item.Type,showTitle:!0,showParentTitle:!1,centerText:!0,overlayText:!1,overlayPlayButton:!0})})}}function renderSimilarItems(page,item,context){var similarCollapsible=page.querySelector("#similarCollapsible");if(similarCollapsible){if("Movie"!=item.Type&&"Trailer"!=item.Type&&"Series"!=item.Type&&"Program"!=item.Type&&"Recording"!=item.Type&&"Game"!=item.Type&&"MusicAlbum"!=item.Type&&"MusicArtist"!=item.Type&&"ChannelVideoItem"!=item.Type)return void similarCollapsible.classList.add("hide");similarCollapsible.classList.remove("hide");var shape="MusicAlbum"==item.Type||"MusicArtist"==item.Type?"square":"portrait",apiClient=connectionManager.getApiClient(item.ServerId),options={userId:apiClient.getCurrentUserId(),limit:"MusicAlbum"==item.Type||"MusicArtist"==item.Type?8:10,fields:"PrimaryImageAspectRatio,UserData,CanDelete"};"MusicAlbum"==item.Type&&item.AlbumArtists&&item.AlbumArtists.length&&(options.ExcludeArtistIds=item.AlbumArtists[0].Id),apiClient.getSimilarItems(item.Id,options).then(function(result){if(!result.Items.length)return void similarCollapsible.classList.add("hide");similarCollapsible.classList.remove("hide");var html="";html+='';var supportsImageAnalysis=appHost.supports("imageanalysis"),cardLayout=supportsImageAnalysis&&("MusicAlbum"==item.Type||"Game"==item.Type||"MusicArtist"==item.Type);cardLayout=!1,html+=cardBuilder.getCardsHtml({items:result.Items,shape:shape,showParentTitle:"MusicAlbum"==item.Type,centerText:!cardLayout,showTitle:"MusicAlbum"==item.Type||"Game"==item.Type||"MusicArtist"==item.Type,context:context,lazy:!0,showDetailsMenu:!0,coverImage:"MusicAlbum"==item.Type||"MusicArtist"==item.Type,overlayPlayButton:!0,cardLayout:cardLayout,vibrant:cardLayout&&supportsImageAnalysis}),html+="
";var similarContent=similarCollapsible.querySelector(".similarContent");similarContent.innerHTML=html,imageLoader.lazyChildren(similarContent)})}}function renderSeriesAirTime(page,item,isStatic){var seriesAirTime=page.querySelector("#seriesAirTime");if("Series"!=item.Type)return void seriesAirTime.classList.add("hide");var html="";if(item.AirDays&&item.AirDays.length&&(html+=7==item.AirDays.length?"daily":item.AirDays.map(function(a){return a+"s"}).join(",")),
+item.AirTime&&(html+=" at "+item.AirTime),item.Studios.length)if(isStatic)html+=" on "+item.Studios[0].Name;else{var context=inferContext(item),href=appRouter.getRouteUrl(item.Studios[0],{context:context,itemType:"Studio",serverId:item.ServerId});html+=' on '+item.Studios[0].Name+" "}html?(html=("Ended"==item.Status?"Aired ":"Airs ")+html,seriesAirTime.innerHTML=html,seriesAirTime.classList.remove("hide")):seriesAirTime.classList.add("hide")}function renderTags(page,item){var itemTags=page.querySelector(".itemTags"),tagElements=[],tags=item.Tags||[];"Program"===item.Type&&(tags=[]);for(var i=0,length=tags.length;i',html+=''+datetime.toLocaleDateString(currentStartDate,{weekday:"long",month:"long",day:"numeric"})+" ",html+=''+listView.getListViewHtml({items:currentItems,enableUserDataButtons:!1,showParentTitle:!0,image:!1,showProgramTime:!0,mediaInfo:!1,parentTitleWithTitle:!0})+"
"),currentStartDate=itemStartDate,currentItems=[]),currentItems.push(item)}currentItems.length&&(html+='',html+='
'+datetime.toLocaleDateString(currentStartDate,{weekday:"long",month:"long",day:"numeric"})+" ",html+='
'+listView.getListViewHtml({items:currentItems,enableUserDataButtons:!1,showParentTitle:!0,image:!1,showProgramTime:!0,mediaInfo:!1,parentTitleWithTitle:!0})+"
"),page.querySelector(".programGuide").innerHTML=html}function renderChannelGuide(page,apiClient,item){"TvChannel"===item.Type&&(page.querySelector(".programGuideSection").classList.remove("hide"),apiClient.getLiveTvPrograms({ChannelIds:item.Id,UserId:apiClient.getCurrentUserId(),HasAired:!1,SortBy:"StartDate",EnableTotalRecordCount:!1,EnableImages:!1,ImageTypeLimit:0,EnableUserData:!1}).then(function(result){renderProgramsForChannel(page,result)}))}function inferContext(item){return"Movie"===item.Type||"BoxSet"===item.Type?"movies":"Series"===item.Type||"Season"===item.Type||"Episode"===item.Type?"tvshows":"Game"===item.Type||"GameSystem"===item.Type?"games":"Game"===item.Type||"GameSystem"===item.Type?"games":"MusicArtist"===item.Type||"MusicAlbum"===item.Type?"music":"Program"===item.Type?"livetv":null}function filterItemsByCollectionItemType(items,typeInfo){return items.filter(function(item){return typeInfo.mediaType?item.MediaType==typeInfo.mediaType:item.Type==typeInfo.type})}function renderCollectionItems(page,parentItem,types,items){page.querySelector(".collectionItems").innerHTML="";var i,length;for(i=0,length=types.length;i0}).length});otherTypeItems.length&&renderCollectionItemType(page,parentItem,otherType,otherTypeItems),items.length||renderCollectionItemType(page,parentItem,{name:globalize.translate("HeaderItems")},items);var containers=page.querySelectorAll(".collectionItemsContainer"),notifyRefreshNeeded=function(){renderChildren(page,parentItem)};for(i=0,length=containers.length;i',html+='',html+='
',html+=""+type.name+" ",html+=" ",html+=' ',html+="",html+='';var shape="MusicAlbum"==type.type?getSquareShape(!1):getPortraitShape(!1);html+=cardBuilder.getCardsHtml({items:items,shape:shape,showTitle:!0,centerText:!0,lazy:!0,showDetailsMenu:!0,overlayMoreButton:!0,showAddToCollection:!1,showRemoveFromCollection:!0,collectionId:parentItem.Id}),html+="
",html+="";var collectionItems=page.querySelector(".collectionItems");collectionItems.insertAdjacentHTML("beforeend",html),imageLoader.lazyChildren(collectionItems),collectionItems.querySelector(".btnAddToCollection").addEventListener("click",function(){require(["alert"],function(alert){alert({text:globalize.translate("AddItemToCollectionHelp"),html:globalize.translate("AddItemToCollectionHelp")+''+globalize.translate("ButtonLearnMore")+" "})})})}function renderThemeMedia(page,item){if("SeriesTimer"!==item.Type&&"Timer"!==item.Type&&"Genre"!==item.Type&&"MusicGenre"!==item.Type&&"GameGenre"!==item.Type&&"Studio"!==item.Type&&"Person"!==item.Type){var apiClient=connectionManager.getApiClient(item.ServerId);apiClient.getThemeMedia(apiClient.getCurrentUserId(),item.Id,!0).then(function(result){var themeSongs=result.ThemeSongsResult.OwnerId==item.Id?result.ThemeSongsResult.Items:[],themeVideos=result.ThemeVideosResult.OwnerId==item.Id?result.ThemeVideosResult.Items:[];renderThemeSongs(page,themeSongs),renderThemeVideos(page,themeVideos)})}}function renderThemeSongs(page,items){if(items.length){page.querySelector("#themeSongsCollapsible").classList.remove("hide");var html=listView.getListViewHtml({items:items});page.querySelector("#themeSongsContent").innerHTML=html}else page.querySelector("#themeSongsCollapsible").classList.add("hide")}function renderThemeVideos(page,items,user){if(items.length){page.querySelector("#themeVideosCollapsible").classList.remove("hide");var themeVideosContent=page.querySelector("#themeVideosContent");themeVideosContent.innerHTML=getVideosHtml(items,user),imageLoader.lazyChildren(themeVideosContent)}else page.querySelector("#themeVideosCollapsible").classList.add("hide")}function renderMusicVideos(page,item,user){connectionManager.getApiClient(item.ServerId).getItems(user.Id,{SortBy:"SortName",SortOrder:"Ascending",IncludeItemTypes:"MusicVideo",Recursive:!0,Fields:"DateCreated,CanDelete",AlbumIds:item.Id}).then(function(result){if(result.Items.length){page.querySelector("#musicVideosCollapsible").classList.remove("hide");var musicVideosContent=page.querySelector(".musicVideosContent");musicVideosContent.innerHTML=getVideosHtml(result.Items,user),imageLoader.lazyChildren(musicVideosContent)}else page.querySelector("#musicVideosCollapsible").classList.add("hide")})}function renderAdditionalParts(page,item,user){connectionManager.getApiClient(item.ServerId).getAdditionalVideoParts(user.Id,item.Id).then(function(result){if(result.Items.length){page.querySelector("#additionalPartsCollapsible").classList.remove("hide");var additionalPartsContent=page.querySelector("#additionalPartsContent");additionalPartsContent.innerHTML=getVideosHtml(result.Items,user),imageLoader.lazyChildren(additionalPartsContent)}else page.querySelector("#additionalPartsCollapsible").classList.add("hide")})}function renderScenes(page,item){var chapters=item.Chapters||[];if(chapters.length&&!chapters[0].ImageTag&&(chapters=[]),chapters.length){page.querySelector("#scenesCollapsible").classList.remove("hide");var scenesContent=page.querySelector("#scenesContent");enableScrollX()?scenesContent.classList.add("scrollX"):scenesContent.classList.add("vertical-wrap"),require(["chaptercardbuilder"],function(chaptercardbuilder){chaptercardbuilder.buildChapterCards(item,chapters,{itemsContainer:scenesContent,width:400,backdropShape:getThumbShape(),squareShape:getSquareShape()})})}else page.querySelector("#scenesCollapsible").classList.add("hide")}function renderMediaSources(page,user,item){var html=item.MediaSources.map(function(v){return getMediaSourceHtml(user,item,v)}).join('
');item.MediaSources.length>1&&(html=" "+html),page.querySelector("#mediaInfoContent").innerHTML=html,html?page.querySelector(".audioVideoMediaInfo").classList.remove("hide"):page.querySelector(".audioVideoMediaInfo").classList.add("hide")}function getMediaSourceHtml(user,item,version){var html="";version.Name&&item.MediaSources.length>1&&(html+=''+version.Name+"
");for(var i=0,length=version.MediaStreams.length;i';html+='";var attributes=[];stream.DisplayTitle&&attributes.push(createAttribute("Title",stream.DisplayTitle)),stream.Language&&"Video"!=stream.Type&&attributes.push(createAttribute(globalize.translate("MediaInfoLanguage"),stream.Language)),stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoCodec"),stream.Codec.toUpperCase())),stream.CodecTag&&attributes.push(createAttribute(globalize.translate("MediaInfoCodecTag"),stream.CodecTag)),null!=stream.IsAVC&&attributes.push(createAttribute("AVC",stream.IsAVC?"Yes":"No")),stream.Profile&&attributes.push(createAttribute(globalize.translate("MediaInfoProfile"),stream.Profile)),stream.Level&&attributes.push(createAttribute(globalize.translate("MediaInfoLevel"),stream.Level)),(stream.Width||stream.Height)&&attributes.push(createAttribute(globalize.translate("MediaInfoResolution"),stream.Width+"x"+stream.Height)),stream.AspectRatio&&"mjpeg"!=stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoAspectRatio"),stream.AspectRatio)),"Video"==stream.Type&&(null!=stream.IsAnamorphic&&attributes.push(createAttribute(globalize.translate("MediaInfoAnamorphic"),stream.IsAnamorphic?"Yes":"No")),attributes.push(createAttribute(globalize.translate("MediaInfoInterlaced"),stream.IsInterlaced?"Yes":"No"))),(stream.AverageFrameRate||stream.RealFrameRate)&&attributes.push(createAttribute(globalize.translate("MediaInfoFramerate"),stream.AverageFrameRate||stream.RealFrameRate)),stream.ChannelLayout&&attributes.push(createAttribute(globalize.translate("MediaInfoLayout"),stream.ChannelLayout)),stream.Channels&&attributes.push(createAttribute(globalize.translate("MediaInfoChannels"),stream.Channels+" ch")),stream.BitRate&&"mjpeg"!=stream.Codec&&attributes.push(createAttribute(globalize.translate("MediaInfoBitrate"),parseInt(stream.BitRate/1e3)+" kbps")),stream.SampleRate&&attributes.push(createAttribute(globalize.translate("MediaInfoSampleRate"),stream.SampleRate+" Hz")),stream.VideoRange&&"SDR"!==stream.VideoRange&&attributes.push(createAttribute(globalize.translate("sharedcomponents#VideoRange"),stream.VideoRange)),stream.ColorPrimaries&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorPrimaries"),stream.ColorPrimaries)),stream.ColorSpace&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorSpace"),stream.ColorSpace)),stream.ColorTransfer&&attributes.push(createAttribute(globalize.translate("sharedcomponents#ColorTransfer"),stream.ColorTransfer)),stream.BitDepth&&attributes.push(createAttribute(globalize.translate("MediaInfoBitDepth"),stream.BitDepth+" bit")),stream.PixelFormat&&attributes.push(createAttribute(globalize.translate("MediaInfoPixelFormat"),stream.PixelFormat)),stream.RefFrames&&attributes.push(createAttribute(globalize.translate("MediaInfoRefFrames"),stream.RefFrames)),stream.NalLengthSize&&attributes.push(createAttribute("NAL",stream.NalLengthSize)),"Video"!=stream.Type&&attributes.push(createAttribute(globalize.translate("MediaInfoDefault"),stream.IsDefault?"Yes":"No")),"Subtitle"==stream.Type&&(attributes.push(createAttribute(globalize.translate("MediaInfoForced"),stream.IsForced?"Yes":"No")),attributes.push(createAttribute(globalize.translate("MediaInfoExternal"),stream.IsExternal?"Yes":"No"))),"Video"==stream.Type&&version.Timestamp&&attributes.push(createAttribute(globalize.translate("MediaInfoTimestamp"),version.Timestamp)),html+=attributes.join(" "),html+=""}}if(version.Container&&(html+=''+globalize.translate("MediaInfoContainer")+' '+version.Container+"
"),version.Formats&&version.Formats.length,version.Path&&"Http"!=version.Protocol&&user&&user.Policy.IsAdministrator&&(html+=''+globalize.translate("MediaInfoPath")+' '+version.Path+"
"),version.Size){var size=(version.Size/1048576).toFixed(0);html+=''+globalize.translate("MediaInfoSize")+' '+size+" MB
"}return html}function createAttribute(label,value){return''+label+' '+value+" "}function getVideosHtml(items,user,limit,moreButtonClass){var html=cardBuilder.getCardsHtml({items:items,shape:"auto",showTitle:!0,action:"play",overlayText:!1,centerText:!0,showRuntime:!0});return limit&&items.length>limit&&(html+=''+globalize.translate("ButtonMore")+"
"),html}function renderSpecials(page,item,user,limit){connectionManager.getApiClient(item.ServerId).getSpecialFeatures(user.Id,item.Id).then(function(specials){var specialsContent=page.querySelector("#specialsContent");specialsContent.innerHTML=getVideosHtml(specials,user,limit,"moreSpecials"),imageLoader.lazyChildren(specialsContent)})}function renderCast(page,item,context,limit,isStatic){var people=(item.People||[]).filter(function(p){return"Director"!==p.Type});if(!people.length)return void page.querySelector("#castCollapsible").classList.add("hide");page.querySelector("#castCollapsible").classList.remove("hide");var castContent=page.querySelector("#castContent");enableScrollX()?(castContent.classList.add("scrollX"),limit=32):castContent.classList.add("vertical-wrap");var limitExceeded=limit&&people.length>limit;limitExceeded&&(people=people.slice(0),people.length=Math.min(limit,people.length)),require(["peoplecardbuilder"],function(peoplecardbuilder){peoplecardbuilder.buildPeopleCards(people,{itemsContainer:castContent,coverImage:!0,serverId:item.ServerId,width:160,shape:getPortraitShape()})});var morePeopleButton=page.querySelector(".morePeople");morePeopleButton&&(limitExceeded&&!enableScrollX()?morePeopleButton.classList.remove("hide"):morePeopleButton.classList.add("hide"))}function itemDetailPage(){var self=this;self.setInitialCollapsibleState=setInitialCollapsibleState,self.renderDetails=renderDetails,self.renderCast=renderCast,self.renderMediaSources=renderMediaSources}function bindAll(view,selector,eventName,fn){var i,length,elems=view.querySelectorAll(selector);for(i=0,length=elems.length;i=11&&list.push("cordova/mpvplayer")),list.push("bower_components/emby-webcomponents/htmlaudioplayer/plugin"),"cordova"===self.appMode&&list.push("cordova/chromecast"),"android"===self.appMode&&list.push("cordova/externalplayer"),list.push("bower_components/emby-webcomponents/htmlvideoplayer/plugin"),list.push("bower_components/emby-webcomponents/photoplayer/plugin"),appHost.supports("remotecontrol")&&(list.push("bower_components/emby-webcomponents/sessionplayer"),(browser.chrome||browser.opera)&&list.push("bower_components/emby-webcomponents/chromecast/chromecastplayer")),list.push("bower_components/emby-webcomponents/youtubeplayer/plugin");for(var i=0,length=externalPlugins.length;i=11&&list.push("cordova/mpvplayer")),list.push("bower_components/emby-webcomponents/htmlaudioplayer/plugin"),"cordova"===self.appMode&&list.push("cordova/chromecast"),"android"===self.appMode&&list.push("cordova/externalplayer"),list.push("bower_components/emby-webcomponents/htmlvideoplayer/plugin"),list.push("bower_components/emby-webcomponents/photoplayer/plugin"),appHost.supports("remotecontrol")&&(list.push("bower_components/emby-webcomponents/sessionplayer"),(browser.chrome||browser.opera)&&list.push("bower_components/emby-webcomponents/chromecast/chromecastplayer")),list.push("bower_components/emby-webcomponents/youtubeplayer/plugin");for(var i=0,length=externalPlugins.length;i'+Globalize.translate("HeaderLibraries")+"",html+='';for(var i=0,length=mediaFolders.length;i"+folder.Name+" "}html+="
",page.querySelector(".folderAccess").innerHTML=html;var chkEnableAllFolders=page.querySelector("#chkEnableAllFolders");chkEnableAllFolders.checked=user.Policy.EnableAllFolders,triggerChange(chkEnableAllFolders)}function loadChannels(page,user,channels){var html="";html+=''+Globalize.translate("HeaderChannels")+" ",html+='';for(var i=0,length=channels.length;i"+folder.Name+" "}html+="
",$(".channelAccess",page).show().html(html),channels.length?$(".channelAccessContainer",page).show():$(".channelAccessContainer",page).hide(),$("#chkEnableAllChannels",page).checked(user.Policy.EnableAllChannels).trigger("change")}function loadDevices(page,user,devices){var html="";html+=''+Globalize.translate("HeaderDevices")+" ",html+='';for(var i=0,length=devices.length;i"+device.Name+" - "+device.AppName+" "}html+="
",$(".deviceAccess",page).show().html(html),$("#chkEnableAllDevices",page).checked(user.Policy.EnableAllDevices).trigger("change"),user.Policy.IsAdministrator?page.querySelector(".deviceAccessContainer").classList.add("hide"):page.querySelector(".deviceAccessContainer").classList.remove("hide")}function loadUser(page,user,loggedInUser,mediaFolders,channels,devices){page.querySelector(".username").innerHTML=user.Name,libraryMenu.setTitle(user.Name),loadChannels(page,user,channels),loadMediaFolders(page,user,mediaFolders),loadDevices(page,user,devices),loading.hide()}function onSaveComplete(page){loading.hide(),require(["toast"],function(toast){toast(Globalize.translate("SettingsSaved"))})}function saveUser(user,page){user.Policy.EnableAllFolders=$("#chkEnableAllFolders",page).checked(),user.Policy.EnabledFolders=user.Policy.EnableAllFolders?[]:$(".chkFolder",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.EnableAllChannels=$("#chkEnableAllChannels",page).checked(),user.Policy.EnabledChannels=user.Policy.EnableAllChannels?[]:$(".chkChannel",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.EnableAllDevices=$("#chkEnableAllDevices",page).checked(),user.Policy.EnabledDevices=user.Policy.EnableAllDevices?[]:$(".chkDevice",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.BlockedChannels=null,user.Policy.BlockedMediaFolders=null,ApiClient.updateUserPolicy(user.Id,user.Policy).then(function(){onSaveComplete(page)})}function onSubmit(){var page=$(this).parents(".page");loading.show();var userId=getParameterByName("userId");return ApiClient.getUser(userId).then(function(result){saveUser(result,page)}),!1}$(document).on("pageinit","#userLibraryAccessPage",function(){var page=this;$("#chkEnableAllDevices",page).on("change",function(){this.checked?$(".deviceAccessListContainer",page).hide():$(".deviceAccessListContainer",page).show()}),$("#chkEnableAllChannels",page).on("change",function(){this.checked?$(".channelAccessListContainer",page).hide():$(".channelAccessListContainer",page).show()}),page.querySelector("#chkEnableAllFolders").addEventListener("change",function(){this.checked?page.querySelector(".folderAccessListContainer").classList.add("hide"):page.querySelector(".folderAccessListContainer").classList.remove("hide")}),$(".userLibraryAccessForm").off("submit",onSubmit).on("submit",onSubmit)}).on("pageshow","#userLibraryAccessPage",function(){var page=this;loading.show();var promise1,userId=getParameterByName("userId");if(userId)promise1=ApiClient.getUser(userId);else{var deferred=$.Deferred();deferred.resolveWith(null,[{Configuration:{}}]),promise1=deferred.promise()}var promise2=Dashboard.getCurrentUser(),promise4=ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders",{IsHidden:!1})),promise5=ApiClient.getJSON(ApiClient.getUrl("Channels")),promise6=ApiClient.getJSON(ApiClient.getUrl("Devices",{SupportsPersistentIdentifier:!0}));Promise.all([promise1,promise2,promise4,promise5,promise6]).then(function(responses){loadUser(page,responses[0],responses[1],responses[2].Items,responses[3].Items,responses[4].Items)})})});
\ No newline at end of file
+define(["jQuery","loading","libraryMenu","fnchecked"],function($,loading,libraryMenu){"use strict";function triggerChange(select){var evt=document.createEvent("HTMLEvents");evt.initEvent("change",!1,!0),select.dispatchEvent(evt)}function loadMediaFolders(page,user,mediaFolders){var html="";html+=''+Globalize.translate("HeaderLibraries")+" ",html+='';for(var i=0,length=mediaFolders.length;i"+folder.Name+" "}html+="
",page.querySelector(".folderAccess").innerHTML=html;var chkEnableAllFolders=page.querySelector("#chkEnableAllFolders");chkEnableAllFolders.checked=user.Policy.EnableAllFolders,triggerChange(chkEnableAllFolders)}function loadChannels(page,user,channels){var html="";html+=''+Globalize.translate("HeaderChannels")+" ",html+='';for(var i=0,length=channels.length;i"+folder.Name+" "}html+="
",$(".channelAccess",page).show().html(html),channels.length?$(".channelAccessContainer",page).show():$(".channelAccessContainer",page).hide(),$("#chkEnableAllChannels",page).checked(user.Policy.EnableAllChannels).trigger("change")}function loadDevices(page,user,devices){var html="";html+=''+Globalize.translate("HeaderDevices")+" ",html+='';for(var i=0,length=devices.length;i"+device.Name+" - "+device.AppName+" "}html+="
",$(".deviceAccess",page).show().html(html),$("#chkEnableAllDevices",page).checked(user.Policy.EnableAllDevices).trigger("change"),user.Policy.IsAdministrator?page.querySelector(".deviceAccessContainer").classList.add("hide"):page.querySelector(".deviceAccessContainer").classList.remove("hide")}function loadUser(page,user,loggedInUser,mediaFolders,channels,devices){page.querySelector(".username").innerHTML=user.Name,libraryMenu.setTitle(user.Name),loadChannels(page,user,channels),loadMediaFolders(page,user,mediaFolders),loadDevices(page,user,devices),loading.hide()}function onSaveComplete(page){loading.hide(),require(["toast"],function(toast){toast(Globalize.translate("SettingsSaved"))})}function saveUser(user,page){user.Policy.EnableAllFolders=$("#chkEnableAllFolders",page).checked(),user.Policy.EnabledFolders=user.Policy.EnableAllFolders?[]:$(".chkFolder",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.EnableAllChannels=$("#chkEnableAllChannels",page).checked(),user.Policy.EnabledChannels=user.Policy.EnableAllChannels?[]:$(".chkChannel",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.EnableAllDevices=$("#chkEnableAllDevices",page).checked(),user.Policy.EnabledDevices=user.Policy.EnableAllDevices?[]:$(".chkDevice",page).get().filter(function(c){return c.checked}).map(function(c){return c.getAttribute("data-id")}),user.Policy.BlockedChannels=null,user.Policy.BlockedMediaFolders=null,ApiClient.updateUserPolicy(user.Id,user.Policy).then(function(){onSaveComplete(page)})}function onSubmit(){var page=$(this).parents(".page");loading.show();var userId=getParameterByName("userId");return ApiClient.getUser(userId).then(function(result){saveUser(result,page)}),!1}$(document).on("pageinit","#userLibraryAccessPage",function(){var page=this;$("#chkEnableAllDevices",page).on("change",function(){this.checked?$(".deviceAccessListContainer",page).hide():$(".deviceAccessListContainer",page).show()}),$("#chkEnableAllChannels",page).on("change",function(){this.checked?$(".channelAccessListContainer",page).hide():$(".channelAccessListContainer",page).show()}),page.querySelector("#chkEnableAllFolders").addEventListener("change",function(){this.checked?page.querySelector(".folderAccessListContainer").classList.add("hide"):page.querySelector(".folderAccessListContainer").classList.remove("hide")}),$(".userLibraryAccessForm").off("submit",onSubmit).on("submit",onSubmit)}).on("pageshow","#userLibraryAccessPage",function(){var page=this;loading.show();var promise1,userId=getParameterByName("userId");if(userId)promise1=ApiClient.getUser(userId);else{var deferred=$.Deferred();deferred.resolveWith(null,[{Configuration:{}}]),promise1=deferred.promise()}var promise2=Dashboard.getCurrentUser(),promise4=ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders",{IsHidden:!1})),promise5=ApiClient.getJSON(ApiClient.getUrl("Channels")),promise6=ApiClient.getJSON(ApiClient.getUrl("Devices"));Promise.all([promise1,promise2,promise4,promise5,promise6]).then(function(responses){loadUser(page,responses[0],responses[1],responses[2].Items,responses[3].Items,responses[4].Items)})})});
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
index 8e3b426762..a718425204 100644
--- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
+++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
@@ -61,13 +61,13 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Server.Core.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
+ ..\packages\MediaBrowser.Server.Core.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Controller.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 97e97cc9c1..517241ee56 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -575,15 +575,11 @@ protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult
{
var val = reader.ReadElementContentAsString();
- var hasTrailer = item as IHasTrailers;
- if (hasTrailer != null)
+ if (!string.IsNullOrWhiteSpace(val))
{
- if (!string.IsNullOrWhiteSpace(val))
- {
- val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase);
+ val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase);
- hasTrailer.AddTrailerUrl(val);
- }
+ item.AddTrailerUrl(val);
}
break;
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 89fbcbce84..505fec65fb 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -528,13 +528,9 @@ private void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManager lib
writer.WriteElementString("credits", person);
}
- var hasTrailer = item as IHasTrailers;
- if (hasTrailer != null)
+ foreach (var trailer in item.RemoteTrailers)
{
- foreach (var trailer in hasTrailer.RemoteTrailers)
- {
- writer.WriteElementString("trailer", GetOutputTrailerUrl(trailer.Url));
- }
+ writer.WriteElementString("trailer", GetOutputTrailerUrl(trailer.Url));
}
if (item.CommunityRating.HasValue)
diff --git a/MediaBrowser.XbmcMetadata/packages.config b/MediaBrowser.XbmcMetadata/packages.config
index 1c4aaf7ddf..c26580a70a 100644
--- a/MediaBrowser.XbmcMetadata/packages.config
+++ b/MediaBrowser.XbmcMetadata/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/Mono.Nat/Mono.Nat.csproj b/Mono.Nat/Mono.Nat.csproj
index b5a0436bd9..074b9ab578 100644
--- a/Mono.Nat/Mono.Nat.csproj
+++ b/Mono.Nat/Mono.Nat.csproj
@@ -32,10 +32,10 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/Mono.Nat/packages.config b/Mono.Nat/packages.config
index 76aa4bb8c7..85e552f7ee 100644
--- a/Mono.Nat/packages.config
+++ b/Mono.Nat/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/RSSDP/RSSDP.csproj b/RSSDP/RSSDP.csproj
index a0c4a23306..ab76d3ba03 100644
--- a/RSSDP/RSSDP.csproj
+++ b/RSSDP/RSSDP.csproj
@@ -58,10 +58,10 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/RSSDP/packages.config b/RSSDP/packages.config
index 76aa4bb8c7..85e552f7ee 100644
--- a/RSSDP/packages.config
+++ b/RSSDP/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 54d3c0e92e..9e9d629065 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.4.1.17")]
+[assembly: AssemblyVersion("3.4.1.18")]
diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj
index 417158295f..7c58e11fc7 100644
--- a/SocketHttpListener/SocketHttpListener.csproj
+++ b/SocketHttpListener/SocketHttpListener.csproj
@@ -36,10 +36,10 @@
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Common.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Common.dll
- ..\packages\MediaBrowser.Common.3.3.50-beta\lib\netstandard2.0\MediaBrowser.Model.dll
+ ..\packages\MediaBrowser.Common.3.3.53-beta\lib\netstandard2.0\MediaBrowser.Model.dll
diff --git a/SocketHttpListener/packages.config b/SocketHttpListener/packages.config
index 76aa4bb8c7..85e552f7ee 100644
--- a/SocketHttpListener/packages.config
+++ b/SocketHttpListener/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/ThirdParty/emby/Emby.Server.Connect.dll b/ThirdParty/emby/Emby.Server.Connect.dll
index 28170e317a4f0c71dd228fc63a57297540c1391c..120b3776b9074f8aa3169ba3bba5a9c7e20467f1 100644
GIT binary patch
delta 22255
zcmbt+d3=;b@_zL@?@VSU$z+b)_npZBByt7;g9JkaLAfs_2q-8x3t`ul2~Hx4;*BqO
zfdT?5UMqs@dgQwx=z8FRqALn4Dx$cG_bRU7@2Ps7&o6x5=k2QMuCA`GKHr4a
zFKn$p*>1hA@azvOr;zn?kP7qTRW;G~U^qs6)tkMUPkrhYaKsKSh5zXG3V7#@x6l-x$N;T9rg
ze0a3)mUFd>0}%>TYcv@0Vj`cPw8aIAbU)b^7s@-hh{(Md27s5cI1g_}n5lTb@>4LM
zsM1d@%m}t1V+Hhd=qs`GRY+Oe;&OSL`ht>9SzM-aSs|0A!U9tvGen{BTxzhk)Y8;F
zMngACLlxeRFjJ<2LQ?@Vf-Oc)THbkOR_W8Egl%z8d7F0BNIGS4HQtUeQ>K<8QwuXX
z+m%(VQyA_H8aJiotHs7+Y4w3C(dK~NZx2Q|q5Jh-m)$y1{(i$S=zMn|&L0=N
zl@kuXBe)!iZiBT{SbH86Yd*)~@%(NvGBXQ&867QQ8FCxOh|J9T6)3ZK0yyMI>+aLE
zFsGYWGIyfIZPdb?4BZZ9YUmDN!0mSj@8pEb?+V^!Jd|0RpWQ{hD|k1HopIrK6!ken
zs|;J#^t9Dr9!O@tiGeMnA#?`sF~V63y!S$esLQIh5jvPEjN@4)X=}ht4Xp(x`fb5=
zcqjO^;C)7Ic7xhrv}LEJ|BnoLx((3MjJoV>VXLiR{eO
z`1*2FGK45gusq{VwkyxTrp$+k4%*i=JZ8A3HRAoE_k>vvp7V!ax#a+hH
zoLXO}52isGxOW@oSNLg^?rUpneOFQylIIrfEd1mKvo+t9kPboc`
zcNV0*^UsKB30JGNG?^{AKEFBI5*uwJqADY?px}4f&`{7P+J@O3ZMeChEbTFvZgw2A
zwU#+RXYen^u7VuzVE=tl`MEh=P{WD6`?K0BSocZtMPVG(fB7JY?cx1GzYJk
z7WylfNe%Jv4Cp@H6?zJ(IG-M@fz5H@OtwT1{SC}hj#Xnsacx!Sm|TF|JSJJ0UGv!&
zUk*mckmPh|g|WFfKky7^;L-OiCwTNdXB;Z7_2qSpK2hWfwj13`mc~Q|v$d9HAY%NL
zk}1*1(CHg=S`VXl>4oY42c-$kr*Ot!O4%9jmKL4C&PWaDsR8@%yM$+~>yfv_XP22P
z;P5%%BBNhfenyN>xCJtQIsMMya$|m3ZDyxW!mt)x@kyL74j$N9HeB6rc!SC60iz_i
zFxm(k{RfSxHZ}zp`q#2&IPy4HIP&f@dXzVmbF7#XfEGq)>Y+7YSfSN5_nPvCYR*lL
z^zP@xX<-DDu7$5=-yzHqju=YjINr_)4#($>)QUbuh+=cCXk*Lm!5t7M9H{6r^@J+Y
z({_Sy4kpg1wOj>s2467ltr*hpMaU}dw}qzSt%b25=%Ifg8GH#)m1GOO%tTK>>Iqem
zTERT@=dh-)TO}A3@4`X7t>NImi*@LI?i1OKG
zWNFRs7;Cy^#s-ns?=^!c$)AKEdaGM)bg`3GC1J74?w+Yu7=63v2j1nH1O7nppPcaf
z{lWK)OS;!q!}J(W_=9^{?9;-_VV2Jqx)4SzXoa!nJQaH1c)R)H?;qhBJR!5flg6s^S_vJu#=JJHQn_gIC0?|QEaMb41L78KW14f=gV>jdr9|7
z)SuKfyLz0}m%GMnLc)QJKnl;4>=La7y9?cy5{$-Tl+Cf&Sbd{cVi9#
z@l?aBuBPkoTFr+3=J0yFrlEqZ;^EbR;k636gH_UqQw^+w)B23=99URPeq&%kVd*||
zCE!e2%UwXM1kv_I+1$QOr`1Q>r_-w#L#G+XPwVMB1Wk+Avx@LKVCWNLaL>W&u(70P
z`Ji`Lc0ah}sG1zt{0c}6H_m+O;l>lS3^$(UUN=7PS$kIJaD#tzaNmHAfD;>}H<9QT
zzrYzse`ubF^db#R4wl6mky8tEwcto(eQM0#
z5FR#O>(wJ5F7^05!R^e)c*9(k)Vp>@r%T0-M02j%Kh}noH)bGPlRW0|-x$aaYanCf
z#SG*JV5LPqyo(=#GIC_d
z=9JS|2OjNXjp7u4iaCmt{mB@`2m8c~Vo{WAj^cpjzrZO*abw@?xkq43i7yZuk1z~<
zZV?wT@o$Tm&BPZ>SaIZqB4>
z{xr;_XZPbB-SU2UYNxTeUy6Fc_(#9%V}o=a_q8#-wxD1sYjyorr?BtW*H*#rZ`P*A
z`kiNe@jD+ImK&;n%xe1=SO~7Hwpgp-<+1%Mk~!i_(n8;xt-#Je4}EIf*1tGr4da4Z
z%i};ESFiP77&X~O8cgnGoOgN;A5TzS_wdV4Z;0?jpoO1C;pC7xm6~aD?ljZpWXWm2
zej=qD6A~7dgPjFqCrnIncAny}OMy*)1!C2}$gy_%QFag=f=z1$DKFv2L;rY(GAeMK
z?qe3S1s{|QGWmU=5%o6O2Gm4;08>`qZUwFd=~(ZyF!oG(NcjI@A#b4)`(aKaOY~!B
zkzCh;W@l#+;YW*9UTWq4DK`Ht(frJh1Y-)EZWTE88wG?PlRtjJJ4f~jLa%llY!)s5ZH8jlZjW?+^3jUDaofiVm3vrsLk%&bAY@b(#$pZs5xl+Eie
zoZva}I2o4=>Ng3qzq#^CAy@DO%bm@?;#Gnu=Zao?lmgCWm*|vnLp(`w*r&hba~(*z*Dq?v93Ol#R{$k98H%eXdTAAQt-=
zHG|LU&5@RnnuyJKmz}s4-UWTJr<0D$1HM@>9vR#%wg*p|5xyN9(}UP*%8XzPI5QhP
zIO)u?fD`VLeV>aHyu7&$pKuugRPgLhxtAenn>a}*caLW$7k#s!!M?<#+kPBK2L&!2_s
zId|v?DlV~we4Li~+!n%ZoHg0oLIF<8N?=xKE+Dp0GV^8qu!T}M&C3T{btz1gpmWeK
z4x)a>yrF$nnz3`54zV`lWNs45rJcad
zVX7%fmW^gd`U6zok>>f;O#AKDoNAXjmA9O3(oI(`Y%XuzEK#-xtb)a&tp!3A4el
zI+fQG=~TXky3ct1tVWsHD@R*d(W7om+EdYRbN7tXOI2@E2tICL95JR^Ib}iUQe!4+
z)LK5~z{o+efBzG|{(2x4=PRGdJ&}q|&I(ndHupY@l~QA@ZKzVY#%m4TRG#tQhCH>|
z$QqWd@{NAOijh8l*r;6Gl)6K>CPjOSfD+looZv~S#CT;`?Z|!|Ar3e4#;uga*tluo
ze}Q3!qihn`wO!er&GR|atnI#WUSq199nAJ&lH<1FRfbnu2)CvkL~01vtx*DZuu-Bi
zmcadKRMHKE7CsEis-{_5P11~3+`qbg6V2LELp`D;txOW$xXg(v#06>xVdatGfSWoi
zD15w${RnLjeQXRmo1J{Y*}bxP=$QFq{d5uc_rHzD&d$u{G4a0{#&d?xjYDTws_zW%
z@bn5y&hGx3e~EVYCurJ_^%IVlprSd$SaVLVICEreGTuL@O42-+C63HX?~9_Ryql;W
z$@iW&jvS);8E=j(8o3lr#EumE59_RLF5qB&&8(YD@mHL_9_a-(_wU^w8-qvH7G-n<
zI{GepCxs)x3U;RxiCW{HQ5j|ZVPoiYh5-x%0T?%~;2*_K%uej5~xZ
z_;(02gz6waW!t8l+fc^~rs*f~aa=eLMl=sb5$r6MW`5%lPQr
zTHnAfEl3D97**%xPm~!WIVOa@f$EqU10f`w6rMw{LVGwo*auq6=Rlt)COo2SgvW;S
z=Ettk?_#>{Z_W5F;4ov#n0{)bv0_Y#8eu#$rabK&
zm|*UOusuY}eg-;&BaNTOO!1C_OqL}ZVJ^X5Xx7-gv~$5Ut?atHSv9sH$Tjg^s2-y8RF$SG0w$zRvr6|lRPwhd}E1tNUl$Q&zDb+$8qeo3F$E#6KpQw
zGo71?F9j32d?|Pf<_s|AOcIG?#D7RK(zx_-?u>LZsqo!`KVpOjag47FWf{LtEQzt6HE1o^xv};AC&hdn(CHYg
zA852s>YFFl$1U*2TbFs}A=8{z*!aNYs$Nf`Ru@+3r|^ciF<`6~@=
zNhrX9g6#z+k5s5OHyKtiW4}m)jNVgc_+>%pdfEHX)Ot*)Urp_wHU(PDp^+wz!t{-y
zG1aI$KPPg&)S!hihv?=VtX0EEEu4EY5BB0X@d~z^XJEUjh51t}?BcJn@s6rlap8LO
zQ(Sl$$9ou?4m~s<4h&5Y>xFJ+x?Ey-8@Pc8+q@kq9)r*0jSpP>m5()RuEp50pkpx#
z@I^%nHlgnijM2i(P1IWWbt0v(!--r3N_IdAUkJ)+S=2~*oR+6`x*^JrID<{>0i2Jm
zUN=cHFu*n$^=$Jf;G1b+@S&<}Ou5o~hUBm6x%-cgGe
z4$Ii(=%K|ZUee7`dga-$FYTu5P+>`GURC6t&NPOZ+;h8+>#}rTf$X7+V;Es(%w~ow
zG>2apAeY3*+gN@n7@wOcqX7rX5q;|8r>J+YY|pq^|Kk_n;;x4
z{fXs*`xCoLj_`WZTOk~_(9F4Lv3!o1hXlv(Wq4ch%jFQi*ngst-GCgwGp+b#F5;J8
zkrOFHI|7)?KuZW(Is;hrh=MKw9A$U3F&e=0!kq!k6~{D8C#4acDGkFGm>U+sHkVsA
z#gTS8%qO#fS{S=hJ%k{2ga$}kG1kltC*srmLWH>N_$1G|_>+7uez#yhjpSbfZw0UZ`@yxV-eN5HP#l54d
zomvpP?8*a+v@ml6POXLCCsHu&n0GDJMzE>2Sc-}@K6gxbMA>kiaZOWc92*QT8Ba7-
z4BFau#7EJXg$w3fb}^{jmF_8h^d-?95g1-
zknf;vf@k>?@{{P#`OKf}Kb+~Hq5z{V_yA*snuWMgaFt{#_FoJYpGx|#{&mR?iZ9XA
z9pv(}>KkmmTu|rL)7|uA>9zs~eeU73FK1hUhxEL`$sTIYUR2_zYfD!H%M0$y@X)=v
zOOxGnWo|EU+H+Qyxaq61FLFH;`7Z5Ir-xRQ4~Do$ZeoRpp3S==(@isT&o6h=nYqbD
zZVKe?%y5v;$41N-Bf>dsO1^Crsvl+Jv_G4rWm!9%4r+&S4!YFKdNY)g!=h&}~v#UIFv3&tj~$y^-pm
zFEu?qm9}`6qczv(eSpd?j%QEwDD72(CY5CXLwSsg%QMjK+X`1B{d^{K29;)@`u}($
z4f#cit#eRMQT>kI%Y|E5FNo4RU%o{dgJY-=DJ|Ce93Qh0%|fZ;e1aQUniYGizvR5U&0y
znOj+AW1O49zFC}nTF^o71od?V=n{o7
z9m!=Xh5SNI@iA3Qbwb@PRFE2l`jb%IX}nOqQ^%HMsD2c=l-jVDcr}j;*3xAnJeYD<
z%0P_v`9ggw)ByUEPzQW08%S3OwY!+9GwEuf?#?u+YlNDX$J7wIPNIDZ=3uv8CvqV{#
z)(bUJWNoxjs5{`tfwYVs5b6_=U5|;5jkre2-ANA%^{G&6=ux3A?I$Mvh5jPsPng~|
z)023(;LBp#v$RF1*`jnOq%1pbth*>H=U%K_18EOEOSS?pRlAsahyG7;++pm!C@V>c
z{v-6V@UAm#7nkQGq7>J#TX_GHTAb=_p}sU4FV0f07_%-eji8z@#GpKNFs6cH^^s(~
zO$wH&!$PeR&sC|cXtfZ6@JxcT_t}B8}C!99`Uq~DZd@T13RX{sZ
zZb5pkwCS4!Zd0P5**=qRas~?jeZiFpx1p3Hk@K5*Os}+xoMH_CF26_MgMRELUwNS~@TFY1XgRZ6k{DRo$TKc=mz$bU;-
zKCqv+L%*W#dPlq2HzkmU^CCTBRC6)2HC#;5R;?E}tVq#W;*a6>en=nI1_EEy3HYs@
zoxjY^&cDXN&Ogi1a7vxq%g#mqlZ=R*l$A4?MksPgl}ftcfZ+WOuD&*ojq5O?1e~pL
zQ6p-c9Y!eHf}KvZv!cx_MBF&2N0P*USJ$z7$GAJ3*3tUITCAdRmWd9!xqKSZW{-J!4uMe$tUWs2U-a$)%f7BQ?
zbrW!)x)V4IoTw+Fbw%DR+rSRg9)Z}ba=G3c6;HG?-fG_rDO-wp&G9U7c-&6li~38Q
z)pv}AsL~FdZ*}UNsB>d#?Tn_*+Z>Car!W#{4lS-=hxBWalQ}Qy98k;b|BSKvL!>!8
zO@mI=nmIDNnVrSyu6ayOR}B$!@?qPfz0MWH4yUhB@vzQ;&MWGe!K8^y^vvb8*HYTI!tcZpXqp(V{MMdqGXNsBePp
z_=|x#7WHe;3u=Ky)fArVx6vYt8eTXF)DnwIOqt===?06cOqm@4xxysVf6Q}WFZf_5
zb(!Bz^#z2V!>S2;Uq2lbs*RpZS?>2!b|K5!=(*zC{Q;U|QqE~9?UYQdmh5=ZI)5@1
z7nwQ#UF5+2a*t4l)uZrJB!#{fa;YG;?UYIzggWd>7pk$utZ-4%Bj~VMCguDr&`#-eolr}tr0fZQdW3$p$n5xa{z6JF
zH4DC)UFayHnHDuVwa`&aTP^Cv+)EuLq{_^kFXq1CFQsgY`kVV5e~>0x)TZEme+BKd
zsM#5Z{gsp*G|PaU@zEmsJ|!e6KW|9&pYn#O;xz4Vl8u1kNf*jOT;4kWX1>j(r%#+
ztJx(##@Et8OE$YCJ}Hm`HMM_WFtu9Ltit-h5PGj0Zu3~_FZuO>p;XFWUwbQxO+oCQ?^MV>=QJ$oB
zoIB34sI(+6s8JTh19mh`uqYm|qp1lL>Nl$&L$fU*S3idSU{PHC7`nouxQemVW>H+l
zSi0V#49LdOZ5Fj2vT?M^qK>Av
zXzxUN!J@)w??kb?!|X})x+Po)UM(AJW@tD!DAGHQfu!Z&B|+>G_mtQJ+BR`BY?4+@uSr(xSLY7f>&Y
z`Uo?`G#X%15$AWsUXVjA;V<5HYNB&2%H{Kd8gEh8!57o%0*kr}zL-uITU0+d|3V5`
z)KED8!Y+QAL4USn+@u-QYEcnx(+pZ>k`jnBX}M6#sXe$bFq7^T%An!#)oLa^Y|7G)
z=Pe4%qNmJq2-&Axv*_;@wZhdqX%@X?QC>9ZB6`!JioIS?9D34)5zP4))7}_07t@C^
zYA%juMb6pud5qH8^lgmN+4NtFdJo3TAzM$g3qOZ3b11>0R_3?UC6sJY59LR^Aag8o
zUO_uuN+lN6hSTn))ZL<5f@9TO>SIwi1y|bVb}?<
z7L^pdC-5h7;x`=Nd`b#F7>Ha><1F%@zAb@2(?W~-Q^~V|E9mJ?*^7Ziw5wD0dLT^M
zy;;qNsvMVDE%Y_6Z<)H%n+=M8DXK%Zm|AM1vc+_xMRB<+BlH>H#99Tfq@OH`g%P@O
zP*fJ7)fUCFR{HZ9QCTZpXHhI`qdj#|SsNX)D3)DCTZcqtS5aiAMY3=S1<#5Kmry^8
zV%gR7hhb6K)m=K~8oE+sOK82?8@PrZv~qH}r8IM7wA@l!Xi+S?7VF=+QQ@_8qeZds
zIyyK$D!Y!pwkVb@qcrj=MRTpJTyQmgwlG?7HT`5!EW3vWTppF(LnADT
zW%ttBE26S{yHvP_9uwIT+6%9BP?06{thP6>mUdbNS1lLsFxxwof7ww{WGGM&GH5-=@vgyjax6l!@y`hH^