diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8244490fc5..1668278fae 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -2217,7 +2217,7 @@ public async Task CheckForApplicationUpdate(CancellationTo try { var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser", - "Emby", + "Emby.Releases", ApplicationVersion, updateLevel, ReleaseAssetFilename, diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js index aec9375d78..a3f45d9350 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js @@ -1 +1 @@ -define(["events","apiclient","appStorage"],function(events,apiClientFactory,appStorage){"use strict";function getServerAddress(server,mode){switch(mode){case ConnectionMode.Local:return server.LocalAddress;case ConnectionMode.Manual:return server.ManualAddress;case ConnectionMode.Remote:return server.RemoteAddress;default:return server.ManualAddress||server.LocalAddress||server.RemoteAddress}}function paramsToString(params){var values=[];for(var key in params){var value=params[key];null!==value&&void 0!==value&&""!==value&&values.push(encodeURIComponent(key)+"="+encodeURIComponent(value))}return values.join("&")}function resolveFailure(instance,resolve){resolve({State:"Unavailable",ConnectUser:instance.connectUser()})}function mergeServers(credentialProvider,list1,list2){for(var i=0,length=list2.length;ibVal)return 1}return 0}var defaultTimeout=2e4,ConnectionMode={Local:0,Remote:1,Manual:2},ConnectionManager=function(credentialProvider,appName,appVersion,deviceName,deviceId,capabilities,devicePixelRatio){function onConnectUserSignIn(user){appStorage.removeItem("lastLocalServerId"),connectUser=user,events.trigger(self,"connectusersignedin",[user])}function onAuthenticated(apiClient,result,options,saveCredentials){var credentials=credentialProvider.credentials(),servers=credentials.Servers.filter(function(s){return s.Id===result.ServerId}),server=servers.length?servers[0]:apiClient.serverInfo();return!1!==options.updateDateLastAccessed&&(server.DateLastAccessed=(new Date).getTime()),server.Id=result.ServerId,saveCredentials?(server.UserId=result.User.Id,server.AccessToken=result.AccessToken):(server.UserId=null,server.AccessToken=null),credentialProvider.addOrUpdateServer(credentials.Servers,server),credentialProvider.credentials(credentials),apiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,apiClient.serverInfo(server),afterConnected(apiClient,options),onLocalUserSignIn(server,server.LastConnectionMode,result.User)}function afterConnected(apiClient,options){options=options||{},!1!==options.reportCapabilities&&apiClient.reportCapabilities(capabilities),apiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,!1!==options.enableWebSocket&&(console.log("calling apiClient.ensureWebSocket"),apiClient.ensureWebSocket())}function onLocalUserSignIn(server,connectionMode,user){return self.connectUserId()?appStorage.removeItem("lastLocalServerId"):appStorage.setItem("lastLocalServerId",server.Id),self._getOrAddApiClient(server,connectionMode),(self.onLocalUserSignedIn?self.onLocalUserSignedIn.call(self,user):Promise.resolve()).then(function(){events.trigger(self,"localusersignedin",[user])})}function ensureConnectUser(credentials){return connectUser&&connectUser.Id===credentials.ConnectUserId?Promise.resolve():credentials.ConnectUserId&&credentials.ConnectAccessToken?(connectUser=null,getConnectUser(credentials.ConnectUserId,credentials.ConnectAccessToken).then(function(user){return onConnectUserSignIn(user),Promise.resolve()},function(){return Promise.resolve()})):Promise.resolve()}function getConnectUser(userId,accessToken){if(!userId)throw new Error("null userId");if(!accessToken)throw new Error("null accessToken");return ajax({type:"GET",url:"https://connect.emby.media/service/user?id="+userId,dataType:"json",headers:{"X-Application":appName+"/"+appVersion,"X-Connect-UserToken":accessToken}})}function addAuthenticationInfoFromConnect(server,connectionMode,credentials){if(!server.ExchangeToken)throw new Error("server.ExchangeToken cannot be null");if(!credentials.ConnectUserId)throw new Error("credentials.ConnectUserId cannot be null");var url=getServerAddress(server,connectionMode);url=getEmbyServerUrl(url,"Connect/Exchange?format=json&ConnectUserId="+credentials.ConnectUserId);var auth='MediaBrowser Client="'+appName+'", Device="'+deviceName+'", DeviceId="'+deviceId+'", Version="'+appVersion+'"';return ajax({type:"GET",url:url,dataType:"json",headers:{"X-MediaBrowser-Token":server.ExchangeToken,"X-Emby-Authorization":auth}}).then(function(auth){return server.UserId=auth.LocalUserId,server.AccessToken=auth.AccessToken,auth},function(){return server.UserId=null,server.AccessToken=null,Promise.reject()})}function validateAuthentication(server,connectionMode){var url=getServerAddress(server,connectionMode);return ajax({type:"GET",url:getEmbyServerUrl(url,"System/Info"),dataType:"json",headers:{"X-MediaBrowser-Token":server.AccessToken}}).then(function(systemInfo){return updateServerInfo(server,systemInfo),server.UserId?ajax({type:"GET",url:getEmbyServerUrl(url,"users/"+server.UserId),dataType:"json",headers:{"X-MediaBrowser-Token":server.AccessToken}}).then(function(user){return onLocalUserSignIn(server,connectionMode,user),Promise.resolve()},function(){return server.UserId=null,server.AccessToken=null,Promise.resolve()}):Promise.resolve()},function(){return server.UserId=null,server.AccessToken=null,Promise.resolve()})}function getImageUrl(localUser){if(connectUser&&connectUser.ImageUrl)return{url:connectUser.ImageUrl};if(localUser&&localUser.PrimaryImageTag){return{url:self.getApiClient(localUser).getUserImageUrl(localUser.Id,{tag:localUser.PrimaryImageTag,type:"Primary"}),supportsParams:!0}}return{url:null,supportsParams:!1}}function logoutOfServer(apiClient){var serverInfo=apiClient.serverInfo()||{},logoutInfo={serverId:serverInfo.Id};return apiClient.logout().then(function(){events.trigger(self,"localusersignedout",[logoutInfo])},function(){events.trigger(self,"localusersignedout",[logoutInfo])})}function getConnectServers(credentials){return console.log("Begin getConnectServers"),credentials.ConnectAccessToken&&credentials.ConnectUserId?ajax({type:"GET",url:"https://connect.emby.media/service/servers?userId="+credentials.ConnectUserId,dataType:"json",headers:{"X-Application":appName+"/"+appVersion,"X-Connect-UserToken":credentials.ConnectAccessToken}}).then(function(servers){return servers.map(function(i){return{ExchangeToken:i.AccessKey,ConnectServerId:i.Id,Id:i.SystemId,Name:i.Name,RemoteAddress:i.Url,LocalAddress:i.LocalAddress,UserLinkType:"guest"===(i.UserType||"").toLowerCase()?"Guest":"LinkedUser"}})},function(){return credentials.Servers.slice(0).filter(function(s){return s.ExchangeToken})}):Promise.resolve([])}function filterServers(servers,connectServers){return servers.filter(function(server){return!server.ExchangeToken||connectServers.filter(function(connectServer){return server.Id===connectServer.Id}).length>0})}function findServers(){return new Promise(function(resolve,reject){var onFinish=function(foundServers){var servers=foundServers.map(function(foundServer){var info={Id:foundServer.Id,LocalAddress:convertEndpointAddressToManualAddress(foundServer)||foundServer.Address,Name:foundServer.Name};return info.LastConnectionMode=info.ManualAddress?ConnectionMode.Manual:ConnectionMode.Local,info});resolve(servers)};require(["serverdiscovery"],function(serverDiscovery){serverDiscovery.findServers(1e3).then(onFinish,function(){onFinish([])})})})}function convertEndpointAddressToManualAddress(info){if(info.Address&&info.EndpointAddress){var address=info.EndpointAddress.split(":")[0],parts=info.Address.split(":");if(parts.length>1){var portString=parts[parts.length-1];isNaN(parseInt(portString))||(address+=":"+portString)}return normalizeAddress(address)}return null}function testNextConnectionMode(tests,index,server,options,resolve){if(index>=tests.length)return console.log("Tested all connection modes. Failing server connection."),void resolveFailure(self,resolve);var mode=tests[index],address=getServerAddress(server,mode),skipTest=!1,timeout=defaultTimeout;if(mode===ConnectionMode.Local?(!0,timeout=8e3,stringEqualsIgnoreCase(address,server.ManualAddress)&&(console.log("skipping LocalAddress test because it is the same as ManualAddress"),skipTest=!0)):mode===ConnectionMode.Manual&&stringEqualsIgnoreCase(address,server.LocalAddress)&&(!0,timeout=8e3),skipTest||!address)return console.log("skipping test at index "+index),void testNextConnectionMode(tests,index+1,server,options,resolve);console.log("testing connection mode "+mode+" with server "+server.Name),tryConnect(address,timeout).then(function(result){1===compareVersions(self.minServerVersion(),result.Version)?(console.log("minServerVersion requirement not met. Server version: "+result.Version),resolve({State:"ServerUpdateNeeded",Servers:[server]})):server.Id&&result.Id!==server.Id?(console.log("http request succeeded, but found a different server Id than what was expected"),resolveFailure(self,resolve)):(console.log("calling onSuccessfulConnection with connection mode "+mode+" with server "+server.Name),onSuccessfulConnection(server,result,mode,options,resolve))},function(){console.log("test failed for connection mode "+mode+" with server "+server.Name),testNextConnectionMode(tests,index+1,server,options,resolve)})}function onSuccessfulConnection(server,systemInfo,connectionMode,options,resolve){var credentials=credentialProvider.credentials();options=options||{},credentials.ConnectAccessToken&&!1!==options.enableAutoLogin?ensureConnectUser(credentials).then(function(){server.ExchangeToken?addAuthenticationInfoFromConnect(server,connectionMode,credentials).then(function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)},function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}):afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}):afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}function afterConnectValidated(server,credentials,systemInfo,connectionMode,verifyLocalAuthentication,options,resolve){if(options=options||{},!1===options.enableAutoLogin)server.UserId=null,server.AccessToken=null;else if(verifyLocalAuthentication&&server.AccessToken&&!1!==options.enableAutoLogin)return void validateAuthentication(server,connectionMode).then(function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!1,options,resolve)});updateServerInfo(server,systemInfo),server.LastConnectionMode=connectionMode,!1!==options.updateDateLastAccessed&&(server.DateLastAccessed=(new Date).getTime()),credentialProvider.addOrUpdateServer(credentials.Servers,server),credentialProvider.credentials(credentials);var result={Servers:[]};result.ApiClient=self._getOrAddApiClient(server,connectionMode),result.ApiClient.setSystemInfo(systemInfo),result.State=server.AccessToken&&!1!==options.enableAutoLogin?"SignedIn":"ServerSignIn",result.Servers.push(server),result.ApiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,result.ApiClient.updateServerInfo(server,connectionMode),"SignedIn"===result.State&&afterConnected(result.ApiClient,options),resolve(result),events.trigger(self,"connected",[result])}function getCacheKey(feature,apiClient,options){options=options||{};var viewOnly=options.viewOnly,cacheKey="regInfo-"+apiClient.serverId();return viewOnly&&(cacheKey+="-viewonly"),cacheKey}function addAppInfoToConnectRequest(request){request.headers=request.headers||{},request.headers["X-Application"]=appName+"/"+appVersion}function exchangePin(pinInfo){if(!pinInfo)throw new Error("pinInfo cannot be null");var request={type:"POST",url:getConnectUrl("pin/authenticate"),data:{deviceId:pinInfo.DeviceId,pin:pinInfo.Pin},dataType:"json"};return addAppInfoToConnectRequest(request),ajax(request)}console.log("Begin ConnectionManager constructor");var self=this;this._apiClients=[];var connectUser;self.connectUser=function(){return connectUser},self._minServerVersion="3.2.33",self.appVersion=function(){return appVersion},self.appName=function(){return appName},self.capabilities=function(){return capabilities},self.deviceId=function(){return deviceId},self.credentialProvider=function(){return credentialProvider},self.connectUserId=function(){return credentialProvider.credentials().ConnectUserId},self.connectToken=function(){return credentialProvider.credentials().ConnectAccessToken},self.getServerInfo=function(id){return credentialProvider.credentials().Servers.filter(function(s){return s.Id===id})[0]},self.getLastUsedServer=function(){var servers=credentialProvider.credentials().Servers;return servers.sort(function(a,b){return(b.DateLastAccessed||0)-(a.DateLastAccessed||0)}),servers.length?servers[0]:null},self.getLastUsedApiClient=function(){var servers=credentialProvider.credentials().Servers;if(servers.sort(function(a,b){return(b.DateLastAccessed||0)-(a.DateLastAccessed||0)}),!servers.length)return null;var server=servers[0];return self._getOrAddApiClient(server,server.LastConnectionMode)},self.addApiClient=function(apiClient){self._apiClients.push(apiClient);var existingServers=credentialProvider.credentials().Servers.filter(function(s){return stringEqualsIgnoreCase(s.ManualAddress,apiClient.serverAddress())||stringEqualsIgnoreCase(s.LocalAddress,apiClient.serverAddress())||stringEqualsIgnoreCase(s.RemoteAddress,apiClient.serverAddress())}),existingServer=existingServers.length?existingServers[0]:apiClient.serverInfo();if(existingServer.DateLastAccessed=(new Date).getTime(),existingServer.LastConnectionMode=ConnectionMode.Manual,existingServer.ManualAddress=apiClient.serverAddress(),apiClient.serverInfo(existingServer),apiClient.onAuthenticated=function(instance,result){return onAuthenticated(instance,result,{},!0)},!existingServers.length){var credentials=credentialProvider.credentials();credentials.Servers=[existingServer],credentialProvider.credentials(credentials)}events.trigger(self,"apiclientcreated",[apiClient])},self.clearData=function(){console.log("connection manager clearing data"),connectUser=null;var credentials=credentialProvider.credentials();credentials.ConnectAccessToken=null,credentials.ConnectUserId=null,credentials.Servers=[],credentialProvider.credentials(credentials)},self._getOrAddApiClient=function(server,connectionMode){var apiClient=self.getApiClient(server.Id);if(!apiClient){var url=getServerAddress(server,connectionMode);apiClient=new apiClientFactory(url,appName,appVersion,deviceName,deviceId,devicePixelRatio),self._apiClients.push(apiClient),apiClient.serverInfo(server),apiClient.onAuthenticated=function(instance,result){return onAuthenticated(instance,result,{},!0)},events.trigger(self,"apiclientcreated",[apiClient])}return console.log("returning instance from getOrAddApiClient"),apiClient},self.getOrCreateApiClient=function(serverId){var credentials=credentialProvider.credentials(),servers=credentials.Servers.filter(function(s){return stringEqualsIgnoreCase(s.Id,serverId)});if(!servers.length)throw new Error("Server not found: "+serverId);var server=servers[0];return self._getOrAddApiClient(server,server.LastConnectionMode)},self.user=function(apiClient){return new Promise(function(resolve,reject){function onLocalUserDone(e){var image=getImageUrl(localUser);resolve({localUser:localUser,name:connectUser?connectUser.Name:localUser?localUser.Name:null,imageUrl:image.url,supportsImageParams:image.supportsParams,connectUser:connectUser})}function onEnsureConnectUserDone(){apiClient&&apiClient.getCurrentUserId()?apiClient.getCurrentUser().then(function(u){localUser=u,onLocalUserDone()},onLocalUserDone):onLocalUserDone()}var localUser,credentials=credentialProvider.credentials();!credentials.ConnectUserId||!credentials.ConnectAccessToken||apiClient&&apiClient.getCurrentUserId()?onEnsureConnectUserDone():ensureConnectUser(credentials).then(onEnsureConnectUserDone,onEnsureConnectUserDone)})},self.logout=function(){console.log("begin connectionManager loguot");for(var promises=[],i=0,length=self._apiClients.length;ibVal)return 1}return 0}var defaultTimeout=2e4,ConnectionMode={Local:0,Remote:1,Manual:2},ConnectionManager=function(credentialProvider,appName,appVersion,deviceName,deviceId,capabilities,devicePixelRatio){function onConnectUserSignIn(user){appStorage.removeItem("lastLocalServerId"),connectUser=user,events.trigger(self,"connectusersignedin",[user])}function onAuthenticated(apiClient,result,options,saveCredentials){var credentials=credentialProvider.credentials(),servers=credentials.Servers.filter(function(s){return s.Id===result.ServerId}),server=servers.length?servers[0]:apiClient.serverInfo();return!1!==options.updateDateLastAccessed&&(server.DateLastAccessed=(new Date).getTime()),server.Id=result.ServerId,saveCredentials?(server.UserId=result.User.Id,server.AccessToken=result.AccessToken):(server.UserId=null,server.AccessToken=null),credentialProvider.addOrUpdateServer(credentials.Servers,server),credentialProvider.credentials(credentials),apiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,apiClient.serverInfo(server),afterConnected(apiClient,options),onLocalUserSignIn(server,server.LastConnectionMode,result.User)}function afterConnected(apiClient,options){options=options||{},!1!==options.reportCapabilities&&apiClient.reportCapabilities(capabilities),apiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,!1!==options.enableWebSocket&&(console.log("calling apiClient.ensureWebSocket"),apiClient.ensureWebSocket())}function onLocalUserSignIn(server,connectionMode,user){return self.connectUserId()?appStorage.removeItem("lastLocalServerId"):appStorage.setItem("lastLocalServerId",server.Id),self._getOrAddApiClient(server,connectionMode),(self.onLocalUserSignedIn?self.onLocalUserSignedIn.call(self,user):Promise.resolve()).then(function(){events.trigger(self,"localusersignedin",[user])})}function ensureConnectUser(credentials){return connectUser&&connectUser.Id===credentials.ConnectUserId?Promise.resolve():credentials.ConnectUserId&&credentials.ConnectAccessToken?(connectUser=null,getConnectUser(credentials.ConnectUserId,credentials.ConnectAccessToken).then(function(user){return onConnectUserSignIn(user),Promise.resolve()},function(){return Promise.resolve()})):Promise.resolve()}function getConnectUser(userId,accessToken){if(!userId)throw new Error("null userId");if(!accessToken)throw new Error("null accessToken");return ajax({type:"GET",url:"https://connect.emby.media/service/user?id="+userId,dataType:"json",headers:{"X-Application":appName+"/"+appVersion,"X-Connect-UserToken":accessToken}})}function addAuthenticationInfoFromConnect(server,connectionMode,credentials){if(!server.ExchangeToken)throw new Error("server.ExchangeToken cannot be null");if(!credentials.ConnectUserId)throw new Error("credentials.ConnectUserId cannot be null");var url=getServerAddress(server,connectionMode);url=getEmbyServerUrl(url,"Connect/Exchange?format=json&ConnectUserId="+credentials.ConnectUserId);var auth='MediaBrowser Client="'+appName+'", Device="'+deviceName+'", DeviceId="'+deviceId+'", Version="'+appVersion+'"';return ajax({type:"GET",url:url,dataType:"json",headers:{"X-MediaBrowser-Token":server.ExchangeToken,"X-Emby-Authorization":auth}}).then(function(auth){return server.UserId=auth.LocalUserId,server.AccessToken=auth.AccessToken,auth},function(){return server.UserId=null,server.AccessToken=null,Promise.reject()})}function validateAuthentication(server,connectionMode){var url=getServerAddress(server,connectionMode);return ajax({type:"GET",url:getEmbyServerUrl(url,"System/Info"),dataType:"json",headers:{"X-MediaBrowser-Token":server.AccessToken}}).then(function(systemInfo){return updateServerInfo(server,systemInfo),server.UserId?ajax({type:"GET",url:getEmbyServerUrl(url,"users/"+server.UserId),dataType:"json",headers:{"X-MediaBrowser-Token":server.AccessToken}}).then(function(user){return onLocalUserSignIn(server,connectionMode,user)},function(){return server.UserId=null,server.AccessToken=null,Promise.resolve()}):Promise.resolve()},function(){return server.UserId=null,server.AccessToken=null,Promise.resolve()})}function getImageUrl(localUser){if(connectUser&&connectUser.ImageUrl)return{url:connectUser.ImageUrl};if(localUser&&localUser.PrimaryImageTag){return{url:self.getApiClient(localUser).getUserImageUrl(localUser.Id,{tag:localUser.PrimaryImageTag,type:"Primary"}),supportsParams:!0}}return{url:null,supportsParams:!1}}function logoutOfServer(apiClient){var serverInfo=apiClient.serverInfo()||{},logoutInfo={serverId:serverInfo.Id};return apiClient.logout().then(function(){events.trigger(self,"localusersignedout",[logoutInfo])},function(){events.trigger(self,"localusersignedout",[logoutInfo])})}function getConnectServers(credentials){return console.log("Begin getConnectServers"),credentials.ConnectAccessToken&&credentials.ConnectUserId?ajax({type:"GET",url:"https://connect.emby.media/service/servers?userId="+credentials.ConnectUserId,dataType:"json",headers:{"X-Application":appName+"/"+appVersion,"X-Connect-UserToken":credentials.ConnectAccessToken}}).then(function(servers){return servers.map(function(i){return{ExchangeToken:i.AccessKey,ConnectServerId:i.Id,Id:i.SystemId,Name:i.Name,RemoteAddress:i.Url,LocalAddress:i.LocalAddress,UserLinkType:"guest"===(i.UserType||"").toLowerCase()?"Guest":"LinkedUser"}})},function(){return credentials.Servers.slice(0).filter(function(s){return s.ExchangeToken})}):Promise.resolve([])}function filterServers(servers,connectServers){return servers.filter(function(server){return!server.ExchangeToken||connectServers.filter(function(connectServer){return server.Id===connectServer.Id}).length>0})}function findServers(){return new Promise(function(resolve,reject){var onFinish=function(foundServers){var servers=foundServers.map(function(foundServer){var info={Id:foundServer.Id,LocalAddress:convertEndpointAddressToManualAddress(foundServer)||foundServer.Address,Name:foundServer.Name};return info.LastConnectionMode=info.ManualAddress?ConnectionMode.Manual:ConnectionMode.Local,info});resolve(servers)};require(["serverdiscovery"],function(serverDiscovery){serverDiscovery.findServers(1e3).then(onFinish,function(){onFinish([])})})})}function convertEndpointAddressToManualAddress(info){if(info.Address&&info.EndpointAddress){var address=info.EndpointAddress.split(":")[0],parts=info.Address.split(":");if(parts.length>1){var portString=parts[parts.length-1];isNaN(parseInt(portString))||(address+=":"+portString)}return normalizeAddress(address)}return null}function testNextConnectionMode(tests,index,server,options,resolve){if(index>=tests.length)return console.log("Tested all connection modes. Failing server connection."),void resolveFailure(self,resolve);var mode=tests[index],address=getServerAddress(server,mode),skipTest=!1,timeout=defaultTimeout;if(mode===ConnectionMode.Local?(!0,timeout=8e3,stringEqualsIgnoreCase(address,server.ManualAddress)&&(console.log("skipping LocalAddress test because it is the same as ManualAddress"),skipTest=!0)):mode===ConnectionMode.Manual&&stringEqualsIgnoreCase(address,server.LocalAddress)&&(!0,timeout=8e3),skipTest||!address)return console.log("skipping test at index "+index),void testNextConnectionMode(tests,index+1,server,options,resolve);console.log("testing connection mode "+mode+" with server "+server.Name),tryConnect(address,timeout).then(function(result){1===compareVersions(self.minServerVersion(),result.Version)?(console.log("minServerVersion requirement not met. Server version: "+result.Version),resolve({State:"ServerUpdateNeeded",Servers:[server]})):server.Id&&result.Id!==server.Id?(console.log("http request succeeded, but found a different server Id than what was expected"),resolveFailure(self,resolve)):(console.log("calling onSuccessfulConnection with connection mode "+mode+" with server "+server.Name),onSuccessfulConnection(server,result,mode,options,resolve))},function(){console.log("test failed for connection mode "+mode+" with server "+server.Name),testNextConnectionMode(tests,index+1,server,options,resolve)})}function onSuccessfulConnection(server,systemInfo,connectionMode,options,resolve){var credentials=credentialProvider.credentials();options=options||{},credentials.ConnectAccessToken&&!1!==options.enableAutoLogin?ensureConnectUser(credentials).then(function(){server.ExchangeToken?addAuthenticationInfoFromConnect(server,connectionMode,credentials).then(function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)},function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}):afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}):afterConnectValidated(server,credentials,systemInfo,connectionMode,!0,options,resolve)}function afterConnectValidated(server,credentials,systemInfo,connectionMode,verifyLocalAuthentication,options,resolve){if(options=options||{},!1===options.enableAutoLogin)server.UserId=null,server.AccessToken=null;else if(verifyLocalAuthentication&&server.AccessToken&&!1!==options.enableAutoLogin)return void validateAuthentication(server,connectionMode).then(function(){afterConnectValidated(server,credentials,systemInfo,connectionMode,!1,options,resolve)});updateServerInfo(server,systemInfo),server.LastConnectionMode=connectionMode,!1!==options.updateDateLastAccessed&&(server.DateLastAccessed=(new Date).getTime()),credentialProvider.addOrUpdateServer(credentials.Servers,server),credentialProvider.credentials(credentials);var result={Servers:[]};result.ApiClient=self._getOrAddApiClient(server,connectionMode),result.ApiClient.setSystemInfo(systemInfo),result.State=server.AccessToken&&!1!==options.enableAutoLogin?"SignedIn":"ServerSignIn",result.Servers.push(server),result.ApiClient.enableAutomaticBitrateDetection=options.enableAutomaticBitrateDetection,result.ApiClient.updateServerInfo(server,connectionMode),"SignedIn"===result.State&&afterConnected(result.ApiClient,options),resolve(result),events.trigger(self,"connected",[result])}function getCacheKey(feature,apiClient,options){options=options||{};var viewOnly=options.viewOnly,cacheKey="regInfo-"+apiClient.serverId();return viewOnly&&(cacheKey+="-viewonly"),cacheKey}function addAppInfoToConnectRequest(request){request.headers=request.headers||{},request.headers["X-Application"]=appName+"/"+appVersion}function exchangePin(pinInfo){if(!pinInfo)throw new Error("pinInfo cannot be null");var request={type:"POST",url:getConnectUrl("pin/authenticate"),data:{deviceId:pinInfo.DeviceId,pin:pinInfo.Pin},dataType:"json"};return addAppInfoToConnectRequest(request),ajax(request)}console.log("Begin ConnectionManager constructor");var self=this;this._apiClients=[];var connectUser;self.connectUser=function(){return connectUser},self._minServerVersion="3.2.33",self.appVersion=function(){return appVersion},self.appName=function(){return appName},self.capabilities=function(){return capabilities},self.deviceId=function(){return deviceId},self.credentialProvider=function(){return credentialProvider},self.connectUserId=function(){return credentialProvider.credentials().ConnectUserId},self.connectToken=function(){return credentialProvider.credentials().ConnectAccessToken},self.getServerInfo=function(id){return credentialProvider.credentials().Servers.filter(function(s){return s.Id===id})[0]},self.getLastUsedServer=function(){var servers=credentialProvider.credentials().Servers;return servers.sort(function(a,b){return(b.DateLastAccessed||0)-(a.DateLastAccessed||0)}),servers.length?servers[0]:null},self.getLastUsedApiClient=function(){var servers=credentialProvider.credentials().Servers;if(servers.sort(function(a,b){return(b.DateLastAccessed||0)-(a.DateLastAccessed||0)}),!servers.length)return null;var server=servers[0];return self._getOrAddApiClient(server,server.LastConnectionMode)},self.addApiClient=function(apiClient){self._apiClients.push(apiClient);var existingServers=credentialProvider.credentials().Servers.filter(function(s){return stringEqualsIgnoreCase(s.ManualAddress,apiClient.serverAddress())||stringEqualsIgnoreCase(s.LocalAddress,apiClient.serverAddress())||stringEqualsIgnoreCase(s.RemoteAddress,apiClient.serverAddress())}),existingServer=existingServers.length?existingServers[0]:apiClient.serverInfo();if(existingServer.DateLastAccessed=(new Date).getTime(),existingServer.LastConnectionMode=ConnectionMode.Manual,existingServer.ManualAddress=apiClient.serverAddress(),apiClient.serverInfo(existingServer),apiClient.onAuthenticated=function(instance,result){return onAuthenticated(instance,result,{},!0)},!existingServers.length){var credentials=credentialProvider.credentials();credentials.Servers=[existingServer],credentialProvider.credentials(credentials)}events.trigger(self,"apiclientcreated",[apiClient])},self.clearData=function(){console.log("connection manager clearing data"),connectUser=null;var credentials=credentialProvider.credentials();credentials.ConnectAccessToken=null,credentials.ConnectUserId=null,credentials.Servers=[],credentialProvider.credentials(credentials)},self._getOrAddApiClient=function(server,connectionMode){var apiClient=self.getApiClient(server.Id);if(!apiClient){var url=getServerAddress(server,connectionMode);apiClient=new apiClientFactory(url,appName,appVersion,deviceName,deviceId,devicePixelRatio),self._apiClients.push(apiClient),apiClient.serverInfo(server),apiClient.onAuthenticated=function(instance,result){return onAuthenticated(instance,result,{},!0)},events.trigger(self,"apiclientcreated",[apiClient])}return console.log("returning instance from getOrAddApiClient"),apiClient},self.getOrCreateApiClient=function(serverId){var credentials=credentialProvider.credentials(),servers=credentials.Servers.filter(function(s){return stringEqualsIgnoreCase(s.Id,serverId)});if(!servers.length)throw new Error("Server not found: "+serverId);var server=servers[0];return self._getOrAddApiClient(server,server.LastConnectionMode)},self.user=function(apiClient){return new Promise(function(resolve,reject){function onLocalUserDone(e){var image=getImageUrl(localUser);resolve({localUser:localUser,name:connectUser?connectUser.Name:localUser?localUser.Name:null,imageUrl:image.url,supportsImageParams:image.supportsParams,connectUser:connectUser})}function onEnsureConnectUserDone(){apiClient&&apiClient.getCurrentUserId()?apiClient.getCurrentUser().then(function(u){localUser=u,onLocalUserDone()},onLocalUserDone):onLocalUserDone()}var localUser,credentials=credentialProvider.credentials();!credentials.ConnectUserId||!credentials.ConnectAccessToken||apiClient&&apiClient.getCurrentUserId()?onEnsureConnectUserDone():ensureConnectUser(credentials).then(onEnsureConnectUserDone,onEnsureConnectUserDone)})},self.logout=function(){console.log("begin connectionManager loguot");for(var promises=[],i=0,length=self._apiClients.length;i=11)||!(!videoTestElement.canPlayType||!videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/,""))}function supportsTextTracks(){return!(!browser.tizen&&!browser.orsay)||(null==_supportsTextTracks&&(_supportsTextTracks=null!=document.createElement("video").textTracks),_supportsTextTracks)}function canPlayHls(src){return null==_canPlayHls&&(_canPlayHls=canPlayNativeHls()||canPlayHlsWithMSE()),_canPlayHls}function canPlayNativeHls(){if(browser.tizen||browser.orsay)return!0;var media=document.createElement("video");return!(!media.canPlayType("application/x-mpegURL").replace(/no/,"")&&!media.canPlayType("application/vnd.apple.mpegURL").replace(/no/,""))}function canPlayHlsWithMSE(){return null!=window.MediaSource}function canPlayAudioFormat(format){var typeString;if("flac"===format){if(browser.tizen||browser.orsay)return!0;if(browser.edgeUwp)return!0}else if("wma"===format){if(browser.tizen||browser.orsay)return!0;if(browser.edgeUwp)return!0}else{if("opus"===format)return typeString='audio/ogg; codecs="opus"',!!document.createElement("audio").canPlayType(typeString).replace(/no/,"");if("mp2"===format)return!1}if("webma"===format)typeString="audio/webm";else if("mp2"===format)typeString="audio/mpeg";else if("ogg"===format||"oga"===format){if(browser.chrome)return!1;typeString="audio/"+format}else typeString="audio/"+format;return!!document.createElement("audio").canPlayType(typeString).replace(/no/,"")}function testCanPlayMkv(videoTestElement){if(browser.tizen||browser.orsay||browser.web0s)return!0;if(videoTestElement.canPlayType("video/x-matroska").replace(/no/,"")||videoTestElement.canPlayType("video/mkv").replace(/no/,""))return!0;var userAgent=navigator.userAgent.toLowerCase();return browser.chrome?!browser.operaTv&&(-1===userAgent.indexOf("vivaldi")&&-1===userAgent.indexOf("opera")):!!browser.edgeUwp}function testCanPlayTs(){return browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp}function supportsMpeg2Video(){return browser.orsay||browser.tizen||browser.edgeUwp||browser.web0s}function supportsVc1(){return browser.orsay||browser.tizen||browser.edgeUwp}function getDirectPlayProfileForVideoContainer(container,videoAudioCodecs,videoTestElement,options){var supported=!1,profileContainer=container,videoCodecs=[];switch(container){case"asf":supported=browser.tizen||browser.orsay||browser.edgeUwp,videoAudioCodecs=[];break;case"avi":supported=browser.tizen||browser.orsay||browser.edgeUwp;break;case"mpg":case"mpeg":supported=browser.edgeUwp||browser.tizen||browser.orsay;break;case"flv":supported=browser.tizen||browser.orsay;break;case"3gp":case"mts":case"trp":case"vob":case"vro":supported=browser.tizen||browser.orsay;break;case"mov":supported=browser.tizen||browser.orsay||browser.chrome||browser.edgeUwp,videoCodecs.push("h264");break;case"m2ts":supported=browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp,videoCodecs.push("h264"),supportsVc1()&&videoCodecs.push("vc1"),supportsMpeg2Video()&&videoCodecs.push("mpeg2video");break;case"wmv":supported=browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp,videoAudioCodecs=[];break;case"ts":supported=testCanPlayTs(),videoCodecs.push("h264"),canPlayH265(videoTestElement,options)&&(videoCodecs.push("h265"),videoCodecs.push("hevc")),supportsVc1()&&videoCodecs.push("vc1"),supportsMpeg2Video()&&videoCodecs.push("mpeg2video"),profileContainer="ts,mpegts"}return supported?{Container:profileContainer,Type:"Video",VideoCodec:videoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}:null}function getGlobalMaxVideoBitrate(){var userAgent=navigator.userAgent.toLowerCase();if(browser.chromecast){return-1!==userAgent.indexOf("aarch64")?null:self.screen&&self.screen.width>=3800?null:3e7}var isTizenFhd=!1;if(browser.tizen)try{isTizenFhd=!webapis.productinfo.isUdPanelSupported(),console.log("isTizenFhd = "+isTizenFhd)}catch(error){console.log("isUdPanelSupported() error code = "+error.code)}return browser.ps4?8e6:browser.xboxOne?12e6:browser.edgeUwp?null:browser.tizen&&isTizenFhd?2e7:null}function supportsAc3(videoTestElement){return!!(browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s)||videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/,"")&&!browser.osx&&!browser.iOS}function supportsEac3(videoTestElement){return!!(browser.tizen||browser.orsay||browser.web0s)||videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/,"")}var _supportsTextTracks,_canPlayHls;return function(options){options=options||{};var physicalAudioChannels=options.audioChannels||(browser.tv||browser.ps4||browser.xboxOne||browser.chromecast?6:2),videoTestElement=document.createElement("video"),canPlayVp8=videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/,""),canPlayVp9=videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/,""),webmAudioCodecs=["vorbis"],canPlayMkv=testCanPlayMkv(videoTestElement),profile={};profile.MaxStreamingBitrate=12e7,profile.MaxStaticBitrate=1e8,profile.MusicStreamingTranscodingBitrate=Math.min(12e7,192e3),profile.DirectPlayProfiles=[];var videoAudioCodecs=[],hlsVideoAudioCodecs=[],supportsMp3VideoAudio=videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/,"")||videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/,""),supportsMp2VideoAudio=browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s,maxVideoWidth=browser.xboxOne&&self.screen?self.screen.width:null;options.maxVideoWidth&&(maxVideoWidth=options.maxVideoWidth);var canPlayAacVideoAudio=videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/,"");if(canPlayAacVideoAudio&&browser.chromecast&&videoAudioCodecs.push("aac"),supportsAc3(videoTestElement)){videoAudioCodecs.push("ac3");var eAc3=supportsEac3(videoTestElement);eAc3&&videoAudioCodecs.push("eac3");(!browser.edge||!browser.touch||browser.edgeUwp)&&(hlsVideoAudioCodecs.push("ac3"),eAc3&&hlsVideoAudioCodecs.push("eac3"))}supportsMp3VideoAudio&&(videoAudioCodecs.push("mp3"),browser.ps4||physicalAudioChannels<=2&&hlsVideoAudioCodecs.push("mp3")),canPlayAacVideoAudio&&(-1===videoAudioCodecs.indexOf("aac")&&videoAudioCodecs.push("aac"),hlsVideoAudioCodecs.push("aac")),supportsMp3VideoAudio&&(browser.ps4||-1===hlsVideoAudioCodecs.indexOf("mp3")&&hlsVideoAudioCodecs.push("mp3")),supportsMp2VideoAudio&&videoAudioCodecs.push("mp2"),(browser.tizen||browser.orsay||browser.web0s||options.supportsDts)&&(videoAudioCodecs.push("dca"),videoAudioCodecs.push("dts")),(browser.tizen||browser.orsay)&&(videoAudioCodecs.push("pcm_s16le"),videoAudioCodecs.push("pcm_s24le")),options.supportsTrueHd&&videoAudioCodecs.push("truehd"),(browser.tizen||browser.orsay)&&videoAudioCodecs.push("aac_latm"),canPlayAudioFormat("opus")&&(videoAudioCodecs.push("opus"),hlsVideoAudioCodecs.push("opus"),webmAudioCodecs.push("opus")),canPlayAudioFormat("flac")&&videoAudioCodecs.push("flac"),videoAudioCodecs=videoAudioCodecs.filter(function(c){return-1===(options.disableVideoAudioCodecs||[]).indexOf(c)}),hlsVideoAudioCodecs=hlsVideoAudioCodecs.filter(function(c){return-1===(options.disableHlsVideoAudioCodecs||[]).indexOf(c)});var mp4VideoCodecs=[],hlsVideoCodecs=[];canPlayH264(videoTestElement)&&(mp4VideoCodecs.push("h264"),hlsVideoCodecs.push("h264")),canPlayH265(videoTestElement,options)&&(mp4VideoCodecs.push("h265"),mp4VideoCodecs.push("hevc"),browser.tizen&&(hlsVideoCodecs.push("h265"),hlsVideoCodecs.push("hevc"))),supportsMpeg2Video()&&mp4VideoCodecs.push("mpeg2video"),supportsVc1()&&mp4VideoCodecs.push("vc1"),(browser.tizen||browser.orsay)&&mp4VideoCodecs.push("msmpeg4v2"),canPlayVp8&&mp4VideoCodecs.push("vp8"),canPlayVp9&&mp4VideoCodecs.push("vp9"),(canPlayVp8||browser.tizen||browser.orsay)&&videoAudioCodecs.push("vorbis"),mp4VideoCodecs.length&&profile.DirectPlayProfiles.push({Container:"mp4,m4v",Type:"Video",VideoCodec:mp4VideoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}),canPlayMkv&&mp4VideoCodecs.length&&profile.DirectPlayProfiles.push({Container:"mkv",Type:"Video",VideoCodec:mp4VideoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}),["m2ts","wmv","ts","asf","avi","mpg","mpeg","flv","3gp","mts","trp","vob","vro","mov"].map(function(container){return getDirectPlayProfileForVideoContainer(container,videoAudioCodecs,videoTestElement,options)}).filter(function(i){return null!=i}).forEach(function(i){profile.DirectPlayProfiles.push(i)}),["opus","mp3","mp2","aac","flac","alac","webma","wma","wav","ogg","oga"].filter(canPlayAudioFormat).forEach(function(audioFormat){"mp2"===audioFormat?profile.DirectPlayProfiles.push({Container:"mp2,mp3",Type:"Audio",AudioCodec:audioFormat}):"mp3"===audioFormat?profile.DirectPlayProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat}):profile.DirectPlayProfiles.push({Container:"webma"===audioFormat?"webma,webm":audioFormat,Type:"Audio"}),"aac"!==audioFormat&&"alac"!==audioFormat||profile.DirectPlayProfiles.push({Container:"m4a",AudioCodec:audioFormat,Type:"Audio"})}),canPlayVp8&&profile.DirectPlayProfiles.push({Container:"webm",Type:"Video",AudioCodec:webmAudioCodecs.join(","),VideoCodec:"VP8"}),canPlayVp9&&profile.DirectPlayProfiles.push({Container:"webm",Type:"Video",AudioCodec:webmAudioCodecs.join(","),VideoCodec:"VP9"}),profile.TranscodingProfiles=[];var hlsBreakOnNonKeyFrames=!(!(browser.iOS||browser.osx||browser.edge)&&canPlayNativeHls());canPlayHls()&&!1!==browser.enableHlsAudio&&profile.TranscodingProfiles.push({Container:!canPlayNativeHls()||browser.edge||browser.android?"ts":"aac",Type:"Audio",AudioCodec:"aac",Context:"Streaming",Protocol:"hls",MaxAudioChannels:physicalAudioChannels.toString(),MinSegments:browser.iOS||browser.osx?"2":"1",BreakOnNonKeyFrames:hlsBreakOnNonKeyFrames}),["aac","mp3","opus","wav"].filter(canPlayAudioFormat).forEach(function(audioFormat){profile.TranscodingProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat,Context:"Streaming",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()})}),["opus","mp3","aac","wav"].filter(canPlayAudioFormat).forEach(function(audioFormat){profile.TranscodingProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat,Context:"Static",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()})}),!canPlayMkv||browser.tizen||browser.orsay||!1===options.enableMkvProgressive||profile.TranscodingProfiles.push({Container:"mkv",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:mp4VideoCodecs.join(","),Context:"Streaming",MaxAudioChannels:physicalAudioChannels.toString(),CopyTimestamps:!0}),canPlayMkv&&profile.TranscodingProfiles.push({Container:"mkv",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:mp4VideoCodecs.join(","),Context:"Static",MaxAudioChannels:physicalAudioChannels.toString(),CopyTimestamps:!0}),canPlayHls()&&!1!==options.enableHls&&profile.TranscodingProfiles.push({Container:"ts",Type:"Video",AudioCodec:hlsVideoAudioCodecs.join(","),VideoCodec:hlsVideoCodecs.join(","),Context:"Streaming",Protocol:"hls",MaxAudioChannels:physicalAudioChannels.toString(),MinSegments:browser.iOS||browser.osx?"2":"1",BreakOnNonKeyFrames:hlsBreakOnNonKeyFrames}),canPlayVp8&&profile.TranscodingProfiles.push({Container:"webm",Type:"Video",AudioCodec:"vorbis",VideoCodec:"vpx",Context:"Streaming",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()}),profile.TranscodingProfiles.push({Container:"mp4",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:"h264",Context:"Static",Protocol:"http"}),profile.ContainerProfiles=[],profile.CodecProfiles=[];var supportsSecondaryAudio=browser.tizen||browser.orsay||browser.edge||browser.msie,aacCodecProfileConditions=[];videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/,"")||aacCodecProfileConditions.push({Condition:"NotEquals",Property:"AudioProfile",Value:"HE-AAC"}),supportsSecondaryAudio||aacCodecProfileConditions.push({Condition:"Equals",Property:"IsSecondaryAudio",Value:"false",IsRequired:"false"}),browser.chromecast&&aacCodecProfileConditions.push({Condition:"LessThanEqual",Property:"AudioChannels",Value:"2",IsRequired:!0}),aacCodecProfileConditions.length&&profile.CodecProfiles.push({Type:"VideoAudio",Codec:"aac",Conditions:aacCodecProfileConditions}),supportsSecondaryAudio||profile.CodecProfiles.push({Type:"VideoAudio",Conditions:[{Condition:"Equals",Property:"IsSecondaryAudio",Value:"false",IsRequired:"false"}]});var maxH264Level=browser.chromecast?42:51,h264Profiles="high|main|baseline|constrained baseline";maxH264Level>=51&&browser.chrome&&!browser.osx&&(h264Profiles+="|high 10"),profile.CodecProfiles.push({Type:"Video",Codec:"h264",Conditions:[{Condition:"NotEquals",Property:"IsAnamorphic",Value:"true",IsRequired:!1},{Condition:"EqualsAny",Property:"VideoProfile",Value:h264Profiles},{Condition:"LessThanEqual",Property:"VideoLevel",Value:maxH264Level.toString()}]}),browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s||(profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"NotEquals",Property:"IsAVC",Value:"false",IsRequired:!1}),profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"NotEquals",Property:"IsInterlaced",Value:"true",IsRequired:!1})),maxVideoWidth&&profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"LessThanEqual",Property:"Width",Value:maxVideoWidth.toString(),IsRequired:!1});var globalMaxVideoBitrate=(getGlobalMaxVideoBitrate()||"").toString(),h264MaxVideoBitrate=globalMaxVideoBitrate;h264MaxVideoBitrate&&profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"LessThanEqual",Property:"VideoBitrate",Value:h264MaxVideoBitrate,IsRequired:!0});var globalVideoConditions=[];return globalMaxVideoBitrate&&globalVideoConditions.push({Condition:"LessThanEqual",Property:"VideoBitrate",Value:globalMaxVideoBitrate}),maxVideoWidth&&globalVideoConditions.push({Condition:"LessThanEqual",Property:"Width",Value:maxVideoWidth.toString(),IsRequired:!1}),globalVideoConditions.length&&profile.CodecProfiles.push({Type:"Video",Conditions:globalVideoConditions}),browser.chromecast&&profile.CodecProfiles.push({Type:"Audio",Codec:"flac",Conditions:[{Condition:"LessThanEqual",Property:"AudioSampleRate",Value:"96000"}]}),profile.SubtitleProfiles=[],supportsTextTracks()&&profile.SubtitleProfiles.push({Format:"vtt",Method:"External"}),profile.ResponseProfiles=[],profile.ResponseProfiles.push({Type:"Video",Container:"m4v",MimeType:"video/mp4"}),profile}}); \ No newline at end of file +define(["browser"],function(browser){"use strict";function canPlayH264(videoTestElement){return!(!videoTestElement.canPlayType||!videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,""))}function canPlayH265(videoTestElement,options){if(browser.tizen||browser.orsay||browser.xboxOne||browser.web0s||options.supportsHevc)return!0;var userAgent=navigator.userAgent.toLowerCase();if(browser.chromecast){if(-1!==userAgent.indexOf("aarch64"))return!0}return!!(browser.iOS&&(browser.iOSVersion||0)>=11)||!(!videoTestElement.canPlayType||!videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/,""))}function supportsTextTracks(){return!(!browser.tizen&&!browser.orsay)||(null==_supportsTextTracks&&(_supportsTextTracks=null!=document.createElement("video").textTracks),_supportsTextTracks)}function canPlayHls(src){return null==_canPlayHls&&(_canPlayHls=canPlayNativeHls()||canPlayHlsWithMSE()),_canPlayHls}function canPlayNativeHls(){if(browser.tizen||browser.orsay)return!0;var media=document.createElement("video");return!(!media.canPlayType("application/x-mpegURL").replace(/no/,"")&&!media.canPlayType("application/vnd.apple.mpegURL").replace(/no/,""))}function canPlayHlsWithMSE(){return null!=window.MediaSource}function canPlayAudioFormat(format){var typeString;if("flac"===format){if(browser.tizen||browser.orsay)return!0;if(browser.edgeUwp)return!0}else if("wma"===format){if(browser.tizen||browser.orsay)return!0;if(browser.edgeUwp)return!0}else{if("opus"===format)return typeString='audio/ogg; codecs="opus"',!!document.createElement("audio").canPlayType(typeString).replace(/no/,"");if("mp2"===format)return!1}if("webma"===format)typeString="audio/webm";else if("mp2"===format)typeString="audio/mpeg";else if("ogg"===format||"oga"===format){if(browser.chrome)return!1;typeString="audio/"+format}else typeString="audio/"+format;return!!document.createElement("audio").canPlayType(typeString).replace(/no/,"")}function testCanPlayMkv(videoTestElement){if(browser.tizen||browser.orsay||browser.web0s)return!0;if(videoTestElement.canPlayType("video/x-matroska").replace(/no/,"")||videoTestElement.canPlayType("video/mkv").replace(/no/,""))return!0;var userAgent=navigator.userAgent.toLowerCase();return browser.chrome?!browser.operaTv&&(-1===userAgent.indexOf("vivaldi")&&-1===userAgent.indexOf("opera")):!!browser.edgeUwp}function testCanPlayTs(){return browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp}function supportsMpeg2Video(){return browser.orsay||browser.tizen||browser.edgeUwp||browser.web0s}function supportsVc1(){return browser.orsay||browser.tizen||browser.edgeUwp}function getDirectPlayProfileForVideoContainer(container,videoAudioCodecs,videoTestElement,options){var supported=!1,profileContainer=container,videoCodecs=[];switch(container){case"asf":supported=browser.tizen||browser.orsay||browser.edgeUwp,videoAudioCodecs=[];break;case"avi":supported=browser.tizen||browser.orsay||browser.edgeUwp;break;case"mpg":case"mpeg":supported=browser.edgeUwp||browser.tizen||browser.orsay;break;case"flv":supported=browser.tizen||browser.orsay;break;case"3gp":case"mts":case"trp":case"vob":case"vro":supported=browser.tizen||browser.orsay;break;case"mov":supported=browser.tizen||browser.orsay||browser.chrome||browser.edgeUwp,videoCodecs.push("h264");break;case"m2ts":supported=browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp,videoCodecs.push("h264"),supportsVc1()&&videoCodecs.push("vc1"),supportsMpeg2Video()&&videoCodecs.push("mpeg2video");break;case"wmv":supported=browser.tizen||browser.orsay||browser.web0s||browser.edgeUwp,videoAudioCodecs=[];break;case"ts":supported=testCanPlayTs(),videoCodecs.push("h264"),canPlayH265(videoTestElement,options)&&(videoCodecs.push("h265"),videoCodecs.push("hevc")),supportsVc1()&&videoCodecs.push("vc1"),supportsMpeg2Video()&&videoCodecs.push("mpeg2video"),profileContainer="ts,mpegts"}return supported?{Container:profileContainer,Type:"Video",VideoCodec:videoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}:null}function getGlobalMaxVideoBitrate(){var userAgent=navigator.userAgent.toLowerCase();if(browser.chromecast){return-1!==userAgent.indexOf("aarch64")?null:self.screen&&self.screen.width>=3800?null:3e7}var isTizenFhd=!1;if(browser.tizen)try{isTizenFhd=!webapis.productinfo.isUdPanelSupported(),console.log("isTizenFhd = "+isTizenFhd)}catch(error){console.log("isUdPanelSupported() error code = "+error.code)}return browser.ps4?8e6:browser.xboxOne?12e6:browser.edgeUwp?null:browser.tizen&&isTizenFhd?2e7:null}function supportsAc3(videoTestElement){return!!(browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s)||videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/,"")&&!browser.osx&&!browser.iOS}function supportsEac3(videoTestElement){return!!(browser.tizen||browser.orsay||browser.web0s)||videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/,"")}var _supportsTextTracks,_canPlayHls;return function(options){options=options||{};var physicalAudioChannels=options.audioChannels||(browser.tv||browser.ps4||browser.xboxOne||browser.chromecast?6:2),videoTestElement=document.createElement("video"),canPlayVp8=videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/,""),canPlayVp9=videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/,""),webmAudioCodecs=["vorbis"],canPlayMkv=testCanPlayMkv(videoTestElement),profile={};profile.MaxStreamingBitrate=12e7,profile.MaxStaticBitrate=1e8,profile.MusicStreamingTranscodingBitrate=Math.min(12e7,192e3),profile.DirectPlayProfiles=[];var videoAudioCodecs=[],hlsVideoAudioCodecs=[],supportsMp3VideoAudio=videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/,"")||videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/,""),supportsMp2VideoAudio=browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s,maxVideoWidth=browser.xboxOne&&self.screen?self.screen.width:null;options.maxVideoWidth&&(maxVideoWidth=options.maxVideoWidth);var canPlayAacVideoAudio=videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/,"");if(canPlayAacVideoAudio&&browser.chromecast&&videoAudioCodecs.push("aac"),supportsAc3(videoTestElement)){videoAudioCodecs.push("ac3");var eAc3=supportsEac3(videoTestElement);eAc3&&videoAudioCodecs.push("eac3");(!browser.edge||!browser.touch||browser.edgeUwp)&&(hlsVideoAudioCodecs.push("ac3"),eAc3&&hlsVideoAudioCodecs.push("eac3"))}canPlayAacVideoAudio&&browser.chromecast&&-1===videoAudioCodecs.indexOf("aac")&&videoAudioCodecs.push("aac"),supportsMp3VideoAudio&&(videoAudioCodecs.push("mp3"),browser.ps4||physicalAudioChannels<=2&&hlsVideoAudioCodecs.push("mp3")),canPlayAacVideoAudio&&(-1===videoAudioCodecs.indexOf("aac")&&videoAudioCodecs.push("aac"),hlsVideoAudioCodecs.push("aac")),supportsMp3VideoAudio&&(browser.ps4||-1===hlsVideoAudioCodecs.indexOf("mp3")&&hlsVideoAudioCodecs.push("mp3")),supportsMp2VideoAudio&&videoAudioCodecs.push("mp2"),(browser.tizen||browser.orsay||browser.web0s||options.supportsDts)&&(videoAudioCodecs.push("dca"),videoAudioCodecs.push("dts")),(browser.tizen||browser.orsay)&&(videoAudioCodecs.push("pcm_s16le"),videoAudioCodecs.push("pcm_s24le")),options.supportsTrueHd&&videoAudioCodecs.push("truehd"),(browser.tizen||browser.orsay)&&videoAudioCodecs.push("aac_latm"),canPlayAudioFormat("opus")&&(videoAudioCodecs.push("opus"),hlsVideoAudioCodecs.push("opus"),webmAudioCodecs.push("opus")),canPlayAudioFormat("flac")&&videoAudioCodecs.push("flac"),videoAudioCodecs=videoAudioCodecs.filter(function(c){return-1===(options.disableVideoAudioCodecs||[]).indexOf(c)}),hlsVideoAudioCodecs=hlsVideoAudioCodecs.filter(function(c){return-1===(options.disableHlsVideoAudioCodecs||[]).indexOf(c)});var mp4VideoCodecs=[],hlsVideoCodecs=[];canPlayH264(videoTestElement)&&(mp4VideoCodecs.push("h264"),hlsVideoCodecs.push("h264")),canPlayH265(videoTestElement,options)&&(mp4VideoCodecs.push("h265"),mp4VideoCodecs.push("hevc"),browser.tizen&&(hlsVideoCodecs.push("h265"),hlsVideoCodecs.push("hevc"))),supportsMpeg2Video()&&mp4VideoCodecs.push("mpeg2video"),supportsVc1()&&mp4VideoCodecs.push("vc1"),(browser.tizen||browser.orsay)&&mp4VideoCodecs.push("msmpeg4v2"),canPlayVp8&&mp4VideoCodecs.push("vp8"),canPlayVp9&&mp4VideoCodecs.push("vp9"),(canPlayVp8||browser.tizen||browser.orsay)&&videoAudioCodecs.push("vorbis"),mp4VideoCodecs.length&&profile.DirectPlayProfiles.push({Container:"mp4,m4v",Type:"Video",VideoCodec:mp4VideoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}),canPlayMkv&&mp4VideoCodecs.length&&profile.DirectPlayProfiles.push({Container:"mkv",Type:"Video",VideoCodec:mp4VideoCodecs.join(","),AudioCodec:videoAudioCodecs.join(",")}),["m2ts","wmv","ts","asf","avi","mpg","mpeg","flv","3gp","mts","trp","vob","vro","mov"].map(function(container){return getDirectPlayProfileForVideoContainer(container,videoAudioCodecs,videoTestElement,options)}).filter(function(i){return null!=i}).forEach(function(i){profile.DirectPlayProfiles.push(i)}),["opus","mp3","mp2","aac","flac","alac","webma","wma","wav","ogg","oga"].filter(canPlayAudioFormat).forEach(function(audioFormat){"mp2"===audioFormat?profile.DirectPlayProfiles.push({Container:"mp2,mp3",Type:"Audio",AudioCodec:audioFormat}):"mp3"===audioFormat?profile.DirectPlayProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat}):profile.DirectPlayProfiles.push({Container:"webma"===audioFormat?"webma,webm":audioFormat,Type:"Audio"}),"aac"!==audioFormat&&"alac"!==audioFormat||profile.DirectPlayProfiles.push({Container:"m4a",AudioCodec:audioFormat,Type:"Audio"})}),canPlayVp8&&profile.DirectPlayProfiles.push({Container:"webm",Type:"Video",AudioCodec:webmAudioCodecs.join(","),VideoCodec:"VP8"}),canPlayVp9&&profile.DirectPlayProfiles.push({Container:"webm",Type:"Video",AudioCodec:webmAudioCodecs.join(","),VideoCodec:"VP9"}),profile.TranscodingProfiles=[];var hlsBreakOnNonKeyFrames=!(!(browser.iOS||browser.osx||browser.edge)&&canPlayNativeHls());canPlayHls()&&!1!==browser.enableHlsAudio&&profile.TranscodingProfiles.push({Container:!canPlayNativeHls()||browser.edge||browser.android?"ts":"aac",Type:"Audio",AudioCodec:"aac",Context:"Streaming",Protocol:"hls",MaxAudioChannels:physicalAudioChannels.toString(),MinSegments:browser.iOS||browser.osx?"2":"1",BreakOnNonKeyFrames:hlsBreakOnNonKeyFrames}),["aac","mp3","opus","wav"].filter(canPlayAudioFormat).forEach(function(audioFormat){profile.TranscodingProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat,Context:"Streaming",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()})}),["opus","mp3","aac","wav"].filter(canPlayAudioFormat).forEach(function(audioFormat){profile.TranscodingProfiles.push({Container:audioFormat,Type:"Audio",AudioCodec:audioFormat,Context:"Static",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()})}),!canPlayMkv||browser.tizen||browser.orsay||!1===options.enableMkvProgressive||profile.TranscodingProfiles.push({Container:"mkv",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:mp4VideoCodecs.join(","),Context:"Streaming",MaxAudioChannels:physicalAudioChannels.toString(),CopyTimestamps:!0}),canPlayMkv&&profile.TranscodingProfiles.push({Container:"mkv",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:mp4VideoCodecs.join(","),Context:"Static",MaxAudioChannels:physicalAudioChannels.toString(),CopyTimestamps:!0}),canPlayHls()&&!1!==options.enableHls&&profile.TranscodingProfiles.push({Container:"ts",Type:"Video",AudioCodec:hlsVideoAudioCodecs.join(","),VideoCodec:hlsVideoCodecs.join(","),Context:"Streaming",Protocol:"hls",MaxAudioChannels:physicalAudioChannels.toString(),MinSegments:browser.iOS||browser.osx?"2":"1",BreakOnNonKeyFrames:hlsBreakOnNonKeyFrames}),canPlayVp8&&profile.TranscodingProfiles.push({Container:"webm",Type:"Video",AudioCodec:"vorbis",VideoCodec:"vpx",Context:"Streaming",Protocol:"http",MaxAudioChannels:physicalAudioChannels.toString()}),profile.TranscodingProfiles.push({Container:"mp4",Type:"Video",AudioCodec:videoAudioCodecs.join(","),VideoCodec:"h264",Context:"Static",Protocol:"http"}),profile.ContainerProfiles=[],profile.CodecProfiles=[];var supportsSecondaryAudio=browser.tizen||browser.orsay||browser.edge||browser.msie,aacCodecProfileConditions=[];videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/,"")||aacCodecProfileConditions.push({Condition:"NotEquals",Property:"AudioProfile",Value:"HE-AAC"}),supportsSecondaryAudio||aacCodecProfileConditions.push({Condition:"Equals",Property:"IsSecondaryAudio",Value:"false",IsRequired:"false"}),browser.chromecast&&aacCodecProfileConditions.push({Condition:"LessThanEqual",Property:"AudioChannels",Value:"2",IsRequired:!0}),aacCodecProfileConditions.length&&profile.CodecProfiles.push({Type:"VideoAudio",Codec:"aac",Conditions:aacCodecProfileConditions}),supportsSecondaryAudio||profile.CodecProfiles.push({Type:"VideoAudio",Conditions:[{Condition:"Equals",Property:"IsSecondaryAudio",Value:"false",IsRequired:"false"}]});var maxH264Level=browser.chromecast?42:51,h264Profiles="high|main|baseline|constrained baseline";maxH264Level>=51&&browser.chrome&&!browser.osx&&(h264Profiles+="|high 10"),profile.CodecProfiles.push({Type:"Video",Codec:"h264",Conditions:[{Condition:"NotEquals",Property:"IsAnamorphic",Value:"true",IsRequired:!1},{Condition:"EqualsAny",Property:"VideoProfile",Value:h264Profiles},{Condition:"LessThanEqual",Property:"VideoLevel",Value:maxH264Level.toString()}]}),browser.edgeUwp||browser.tizen||browser.orsay||browser.web0s||(profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"NotEquals",Property:"IsAVC",Value:"false",IsRequired:!1}),profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"NotEquals",Property:"IsInterlaced",Value:"true",IsRequired:!1})),maxVideoWidth&&profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"LessThanEqual",Property:"Width",Value:maxVideoWidth.toString(),IsRequired:!1});var globalMaxVideoBitrate=(getGlobalMaxVideoBitrate()||"").toString(),h264MaxVideoBitrate=globalMaxVideoBitrate;h264MaxVideoBitrate&&profile.CodecProfiles[profile.CodecProfiles.length-1].Conditions.push({Condition:"LessThanEqual",Property:"VideoBitrate",Value:h264MaxVideoBitrate,IsRequired:!0});var globalVideoConditions=[];return globalMaxVideoBitrate&&globalVideoConditions.push({Condition:"LessThanEqual",Property:"VideoBitrate",Value:globalMaxVideoBitrate}),maxVideoWidth&&globalVideoConditions.push({Condition:"LessThanEqual",Property:"Width",Value:maxVideoWidth.toString(),IsRequired:!1}),globalVideoConditions.length&&profile.CodecProfiles.push({Type:"Video",Conditions:globalVideoConditions}),browser.chromecast&&profile.CodecProfiles.push({Type:"Audio",Codec:"flac",Conditions:[{Condition:"LessThanEqual",Property:"AudioSampleRate",Value:"96000"}]}),profile.SubtitleProfiles=[],supportsTextTracks()&&profile.SubtitleProfiles.push({Format:"vtt",Method:"External"}),profile.ResponseProfiles=[],profile.ResponseProfiles.push({Type:"Video",Container:"m4v",MimeType:"video/mp4"}),profile}}); \ 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 d6a578a09b..fb5b2ad60b 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-flex;-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 .36em;-webkit-transition:none;-o-transition:none;transition:none;border:0 solid transparent;contain:layout style}.layout-tv .cardBox{margin:.5em}@media all and (max-width:50em){.cardBox{margin:.32em .24em}}.card-focuscontent{border:.12em solid transparent;-webkit-border-radius:.12em;border-radius:.12em}.card-focuscontent-large{border-width:.24em}.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.16,1.16);transform:scale(1.16,1.16)}.cardBox-bottompadded{margin-bottom:1.8em!important}.layout-mobile .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-box;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%;-webkit-border-radius:.08em;border-radius:.08em;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;font-size:93%}.cardDefaultText,.cardTextCentered{text-align:center}.cardText-first{padding-top:.3em}.layout-tv .cardText-first{padding-top:.16em}.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}.card:focus .cardText{color:inherit}.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;-webkit-border-radius:100em;border-radius:100em;position:absolute;bottom:0;right:0;margin:0 .35em .65em 0;z-index:1;padding:.5em;background-color:rgba(0,0,0,.7)!important;font-size:84%}.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:2.4px 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)}.cardOverlayButton-texticon{line-height:1;background-color:rgba(0,0,0,.4)!important}.cardOverlayButton-texticon-icon{font-style:normal}.backdropCard,.bannerCard{width:100%}.smallBackdropCard,.squareCard{width:50%}.portraitCard{width:33.333333333333333333333333333333%}.mixedPortraitCard{width:12em}.mixedSquareCard{width:18em}.mixedBackdropCard{width:32em}@media all and (min-width:400px){.backdropCard{width:50%}}@media all and (min-width:500px){.portraitCard,.smallBackdropCard,.squareCard{width:33.333333333333333333333333333333%}}@media all and (min-width:700px){.portraitCard,.squareCard{width:25%}}@media all and (min-width:770px){.backdropCard{width:33.333333333333333333333333333333%}}@media all and (min-width:800px){.bannerCard{width:50%}.portraitCard,.squareCard{width:20%}.smallBackdropCard{width:25%}}@media all and (min-width:1000px){.smallBackdropCard{width:20%}}@media all and (min-width:1200px){.backdropCard{width:25%}.portraitCard,.squareCard{width:16.666666666666666666666666666667%}.bannerCard{width:33.333333333333333333333333333333%}.smallBackdropCard{width:16.666666666666666666666666666667%}}@media all and (min-width:1400px){.portraitCard,.smallBackdropCard,.squareCard{width:14.285714285714285714285714285714%}}@media all and (min-width:1600px){.smallBackdropCard{width:12.5%}.backdropCard{width:20%}.portraitCard,.squareCard{width:12.5%}}@media all and (min-width:1920px){.portraitCard,.squareCard{width:11.111111111111111111111111111111%}}@media all and (min-width:2100px){.backdropCard{width:20%}}@media all and (min-width:2200px){.bannerCard{width:25%}.portraitCard,.squareCard{width:10%}}@media all and (min-width:2500px){.backdropCard{width:16.666666666666666666666666666667%}}.itemsContainer-tv>.backdropCard{width:25%}.itemsContainer-tv>.portraitCard,.itemsContainer-tv>.squareCard{width:16.666666666666666666666666666667%}@media all and (orientation:portrait){.overflowPortraitCard{width:42vw}.overflowBackdropCard,.overflowSmallBackdropCard{width:72vw}.overflowSquareCard{width:42vw}}@media all and (orientation:landscape){.overflowBackdropCard,.overflowSmallBackdropCard{width:23.3vw}.overflowPortraitCard,.overflowSquareCard{width:15.5vw}}@media all and (orientation:portrait) and (min-width:540px){.overflowSmallBackdropCard{width:30vw}}@media all and (orientation:landscape) and (min-width:800px){.overflowSmallBackdropCard{width:15.5vw}}@media all and (orientation:landscape) and (min-width:1700px){.overflowBackdropCard{width:18.5vw}.overflowPortraitCard,.overflowSquareCard{width:11.6vw}}@media all and (orientation:portrait) and (min-width:400px){.overflowPortraitCard{width:31.5vw}}@media all and (orientation:portrait) and (min-width:540px){.overflowBackdropCard{width:64vw}.overflowSquareCard{width:31.5vw}}@media all and (orientation:portrait) and (min-width:640px){.overflowBackdropCard{width:56vw}}@media all and (orientation:portrait) and (min-width:760px){.overflowPortraitCard{width:23vw}.overflowBackdropCard{width:40vw}.overflowSquareCard{width:23vw}}@media all and (orientation:portrait) and (min-width:1200px){.overflowPortraitCard,.overflowSquareCard{width:18vw}}@media all and (orientation:portrait) and (min-width:1400px){.overflowPortraitCard,.overflowSquareCard{width:15vw}.overflowBackdropCard{width:30vw}}@media all and (orientation:portrait) and (min-width:1800px){.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} \ 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-flex;-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:.44em;-webkit-transition:none;-o-transition:none;transition:none;border:0 solid transparent;contain:layout style}.layout-tv .cardBox{margin:.64em}@media all and (max-width:50em){.cardBox{margin:.32em .24em}}.card-focuscontent{border:.12em solid transparent;-webkit-border-radius:.12em;border-radius:.12em}.card-focuscontent-large{border-width:.24em}.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.16,1.16);transform:scale(1.16,1.16)}.cardBox-bottompadded{margin-bottom:1.8em!important}.layout-mobile .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-box;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%;-webkit-border-radius:.08em;border-radius:.08em;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:.3em}.layout-tv .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;-webkit-border-radius:100em;border-radius:100em;position:absolute;bottom:0;right:0;margin:0 .35em .65em 0;z-index:1;padding:.5em;background-color:rgba(0,0,0,.7)!important;font-size:84%}.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:2.4px 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)}.cardOverlayButton-texticon{line-height:1;background-color:rgba(0,0,0,.4)!important}.cardOverlayButton-texticon-icon{font-style:normal}.backdropCard,.bannerCard{width:100%}.smallBackdropCard,.squareCard{width:50%}.portraitCard{width:33.333333333333333333333333333333%}.mixedPortraitCard{width:12em}.mixedSquareCard{width:18em}.mixedBackdropCard{width:32em}@media all and (min-width:400px){.backdropCard{width:50%}}@media all and (min-width:500px){.portraitCard,.smallBackdropCard,.squareCard{width:33.333333333333333333333333333333%}}@media all and (min-width:700px){.portraitCard,.squareCard{width:25%}}@media all and (min-width:770px){.backdropCard{width:33.333333333333333333333333333333%}}@media all and (min-width:800px){.bannerCard{width:50%}.portraitCard,.squareCard{width:20%}.smallBackdropCard{width:25%}}@media all and (min-width:1000px){.smallBackdropCard{width:20%}}@media all and (min-width:1200px){.backdropCard{width:25%}.portraitCard,.squareCard{width:16.666666666666666666666666666667%}.bannerCard{width:33.333333333333333333333333333333%}.smallBackdropCard{width:16.666666666666666666666666666667%}}@media all and (min-width:1400px){.portraitCard,.smallBackdropCard,.squareCard{width:14.285714285714285714285714285714%}}@media all and (min-width:1600px){.smallBackdropCard{width:12.5%}.backdropCard{width:20%}.portraitCard,.squareCard{width:12.5%}}@media all and (min-width:1920px){.portraitCard,.squareCard{width:11.111111111111111111111111111111%}}@media all and (min-width:2100px){.backdropCard{width:20%}}@media all and (min-width:2200px){.bannerCard{width:25%}.portraitCard,.squareCard{width:10%}}@media all and (min-width:2500px){.backdropCard{width:16.666666666666666666666666666667%}}.itemsContainer-tv>.backdropCard{width:25%}.itemsContainer-tv>.portraitCard,.itemsContainer-tv>.squareCard{width:16.666666666666666666666666666667%}@media all and (orientation:portrait){.overflowPortraitCard{width:42vw}.overflowBackdropCard,.overflowSmallBackdropCard{width:72vw}.overflowSquareCard{width:42vw}}@media all and (orientation:landscape){.overflowBackdropCard,.overflowSmallBackdropCard{width:23.3vw}.overflowPortraitCard,.overflowSquareCard{width:15.5vw}}@media all and (orientation:portrait) and (min-width:540px){.overflowSmallBackdropCard{width:30vw}}@media all and (orientation:landscape) and (min-width:800px){.overflowSmallBackdropCard{width:15.5vw}}@media all and (orientation:landscape) and (min-width:1700px){.overflowBackdropCard{width:18.5vw}.overflowPortraitCard,.overflowSquareCard{width:11.6vw}}@media all and (orientation:portrait) and (min-width:400px){.overflowPortraitCard{width:31.5vw}}@media all and (orientation:portrait) and (min-width:540px){.overflowBackdropCard{width:64vw}.overflowSquareCard{width:31.5vw}}@media all and (orientation:portrait) and (min-width:640px){.overflowBackdropCard{width:56vw}}@media all and (orientation:portrait) and (min-width:760px){.overflowPortraitCard{width:23vw}.overflowBackdropCard{width:40vw}.overflowSquareCard{width:23vw}}@media all and (orientation:portrait) and (min-width:1200px){.overflowPortraitCard,.overflowSquareCard{width:18vw}}@media all and (orientation:portrait) and (min-width:1400px){.overflowPortraitCard,.overflowSquareCard{width:15vw}.overflowBackdropCard{width:30vw}}@media all and (orientation:portrait) and (min-width:1800px){.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} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css index 7216328c99..3bdc4e366b 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css @@ -1 +1 @@ -.emby-button,.fab{-webkit-box-sizing:border-box;-webkit-box-align:center}.emby-button,.paper-icon-button-light{text-align:center;font-family:inherit;color:inherit;cursor:pointer;outline:0!important;position:relative}.emby-button{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;box-sizing:border-box;margin:0 .29em;font-size:inherit;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;z-index:0;padding:1em;border:0;vertical-align:middle;-webkit-border-radius:.2em;border-radius:.2em;font-weight:500;-webkit-tap-highlight-color:transparent;text-decoration:none}.emby-button-withripple{overflow:hidden}.emby-button::-moz-focus-inner{border:0}.button-flat{background:0 0;-webkit-box-shadow:none;box-shadow:none}.button-flat:hover{opacity:.5}.button-link{background:0 0;-webkit-box-shadow:none;box-shadow:none;margin:0;padding:0;vertical-align:initial}.button-link-inline{display:inline}.button-link:hover{text-decoration:underline}.emby-button-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.emby-button-focusscale:focus{-webkit-transform:scale(1.16);transform:scale(1.16);z-index:1}.emby-button>i{font-size:1.36em;width:1em;height:1em}.button-link>i{font-size:1em}.fab{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-border-radius:50%;border-radius:50%;padding:.6em;box-sizing:border-box;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;text-align:center;margin:0}.fab>i{height:1em;width:1em;vertical-align:middle;font-size:2.85em}.fab.mini{padding:8px}.fab.mini>i{height:1em;width:1em;font-size:1.72em}.emby-button.block{display:block;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;margin:.25em 0;width:100%}.fab,.raised{-webkit-box-shadow:0 .145em .145em 0 rgba(0,0,0,.14),0 .0725em .3625em 0 rgba(0,0,0,.12),0 .2175em .0725em -.145em rgba(0,0,0,.2);box-shadow:0 .145em .145em 0 rgba(0,0,0,.14),0 .0725em .3625em 0 rgba(0,0,0,.12),0 .2175em .0725em -.145em rgba(0,0,0,.2);-webkit-transition:-webkit-box-shadow .28s cubic-bezier(.4,0,.2,1);-o-transition:box-shadow .28s cubic-bezier(.4,0,.2,1);transition:box-shadow .28s cubic-bezier(.4,0,.2,1)}.fab:focus,.raised:focus{-webkit-box-shadow:0 .58em .725em .0725em rgba(0,0,0,.14),0 .2175em 1.015em .145em rgba(0,0,0,.12),0 .3625em .3625em -.2175em rgba(0,0,0,.4);box-shadow:0 .58em .725em .0725em rgba(0,0,0,.14),0 .2175em 1.015em .145em rgba(0,0,0,.12),0 .3625em .3625em -.2175em rgba(0,0,0,.4)}.raised-small{padding:.75em;font-size:92%}.raised-mini{padding:.44em 1em}.button-flat-mini{padding:.5em .7em}.emby-button>i+span{margin-left:.5em;vertical-align:middle}.paper-icon-button-light{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0 .29em;background:0 0;font-size:inherit;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;z-index:0;min-width:initial;min-height:initial;width:auto;height:auto;padding:8px;border:0;vertical-align:middle;overflow:hidden;-webkit-border-radius:50%;border-radius:50%;-webkit-tap-highlight-color:transparent;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.paper-icon-button-light::-moz-focus-inner{border:0}.paper-icon-button-light[disabled]{opacity:.3}.paper-icon-button-light>i{width:1em;height:1em;font-size:1.66956521739130434em;position:relative;z-index:1;vertical-align:middle}.paper-icon-button-light>img{width:1.72em;max-height:100%;position:relative;z-index:1;vertical-align:middle}.paper-icon-button-light:after{content:'';position:absolute;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .3s ease-out;-o-transition:opacity .3s ease-out;transition:opacity .3s ease-out;background:currentcolor;opacity:0}.paper-icon-button-light:focus:after{opacity:.2}.emby-button-ripple-effect,.paper-icon-button-light-ripple-effect{position:absolute;-webkit-border-radius:50%;border-radius:50%;width:50px;height:50px;top:50%;left:50%;background:currentcolor;-webkit-animation:ripple-animation .8s;animation:ripple-animation .8s;opacity:.25;-webkit-transform-origin:center center;transform-origin:center center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-webkit-keyframes ripple-animation{from{-webkit-transform:none;transform:none;opacity:.5}to{-webkit-transform:scale(20);transform:scale(20);opacity:0}}@keyframes ripple-animation{from{-webkit-transform:none;transform:none;opacity:.5}to{-webkit-transform:scale(20);transform:scale(20);opacity:0}}.emby-button-foreground{position:relative;z-index:1}.icon-button-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.icon-button-focusscale:focus{-webkit-transform:scale(1.3);transform:scale(1.3);z-index:1}.btnFilterWithBubble{position:relative}.filterButtonBubble{color:#fff;position:absolute;top:0;right:0;width:1.6em;height:1.6em;z-index:100000000;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;font-size:82%;-webkit-border-radius:100em;border-radius:100em;-webkit-box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background:#03A9F4;font-weight:700} \ No newline at end of file +.emby-button,.fab{-webkit-box-sizing:border-box;-webkit-box-align:center}.emby-button,.paper-icon-button-light{text-align:center;font-family:inherit;color:inherit;cursor:pointer;outline:0!important;position:relative}.emby-button{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;box-sizing:border-box;margin:0 .29em;font-size:inherit;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;z-index:0;padding:1em;border:0;vertical-align:middle;-webkit-border-radius:.2em;border-radius:.2em;font-weight:500;-webkit-tap-highlight-color:transparent;text-decoration:none}.emby-button-withripple{overflow:hidden}.emby-button::-moz-focus-inner{border:0}.button-flat{background:0 0;-webkit-box-shadow:none;box-shadow:none}.button-flat:hover{opacity:.5}.button-link{background:0 0;-webkit-box-shadow:none;box-shadow:none;margin:0;padding:0;vertical-align:initial}.button-link-inline{display:inline}.button-link:hover{text-decoration:underline}.emby-button-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.emby-button-focusscale:focus{-webkit-transform:scale(1.16);transform:scale(1.16);z-index:1}.emby-button>i{font-size:1.36em;width:1em;height:1em}.button-link>i{font-size:1em}.fab{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-border-radius:50%;border-radius:50%;padding:.6em;box-sizing:border-box;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;text-align:center;margin:0}.fab>i{height:1em;width:1em;vertical-align:middle;font-size:2.85em}.fab.mini{padding:8px}.fab.mini>i{height:1em;width:1em;font-size:1.72em}.emby-button.block{display:block;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;margin:.25em 0;width:100%}.fab,.raised{-webkit-box-shadow:0 .145em .145em 0 rgba(0,0,0,.14),0 .0725em .3625em 0 rgba(0,0,0,.12),0 .2175em .0725em -.145em rgba(0,0,0,.2);box-shadow:0 .145em .145em 0 rgba(0,0,0,.14),0 .0725em .3625em 0 rgba(0,0,0,.12),0 .2175em .0725em -.145em rgba(0,0,0,.2);-webkit-transition:-webkit-box-shadow .28s cubic-bezier(.4,0,.2,1);-o-transition:box-shadow .28s cubic-bezier(.4,0,.2,1);transition:box-shadow .28s cubic-bezier(.4,0,.2,1)}.fab:focus,.raised:focus{-webkit-box-shadow:0 .58em .725em .0725em rgba(0,0,0,.14),0 .2175em 1.015em .145em rgba(0,0,0,.12),0 .3625em .3625em -.2175em rgba(0,0,0,.4);box-shadow:0 .58em .725em .0725em rgba(0,0,0,.14),0 .2175em 1.015em .145em rgba(0,0,0,.12),0 .3625em .3625em -.2175em rgba(0,0,0,.4)}.raised-small{padding:.75em;font-size:92%}.raised-mini{padding:.5em 1em}.button-flat-mini{padding:.5em .7em}.emby-button>i+span{margin-left:.5em;vertical-align:middle}.paper-icon-button-light{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0 .29em;background:0 0;font-size:inherit;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;z-index:0;min-width:initial;min-height:initial;width:auto;height:auto;padding:8px;border:0;vertical-align:middle;overflow:hidden;-webkit-border-radius:50%;border-radius:50%;-webkit-tap-highlight-color:transparent;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.paper-icon-button-light::-moz-focus-inner{border:0}.paper-icon-button-light[disabled]{opacity:.3}.paper-icon-button-light>i{width:1em;height:1em;font-size:1.66956521739130434em;position:relative;z-index:1;vertical-align:middle}.paper-icon-button-light>img{width:1.72em;max-height:100%;position:relative;z-index:1;vertical-align:middle}.paper-icon-button-light:after{content:'';position:absolute;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .3s ease-out;-o-transition:opacity .3s ease-out;transition:opacity .3s ease-out;background:currentcolor;opacity:0}.paper-icon-button-light:focus:after{opacity:.2}.emby-button-ripple-effect,.paper-icon-button-light-ripple-effect{position:absolute;-webkit-border-radius:50%;border-radius:50%;width:50px;height:50px;top:50%;left:50%;background:currentcolor;-webkit-animation:ripple-animation .8s;animation:ripple-animation .8s;opacity:.25;-webkit-transform-origin:center center;transform-origin:center center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-webkit-keyframes ripple-animation{from{-webkit-transform:none;transform:none;opacity:.5}to{-webkit-transform:scale(20);transform:scale(20);opacity:0}}@keyframes ripple-animation{from{-webkit-transform:none;transform:none;opacity:.5}to{-webkit-transform:scale(20);transform:scale(20);opacity:0}}.emby-button-foreground{position:relative;z-index:1}.icon-button-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.icon-button-focusscale:focus{-webkit-transform:scale(1.3);transform:scale(1.3);z-index:1}.btnFilterWithBubble{position:relative}.filterButtonBubble{color:#fff;position:absolute;top:0;right:0;width:1.6em;height:1.6em;z-index:100000000;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;font-size:82%;-webkit-border-radius:100em;border-radius:100em;-webkit-box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background:#03A9F4;font-weight:700} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-select/emby-select.css b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-select/emby-select.css index 5ff84beafd..a2d8822c1b 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-select/emby-select.css +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/emby-select/emby-select.css @@ -1 +1 @@ -.emby-select{display:block;margin:0;margin-bottom:0!important;font-size:110%;font-family:inherit;font-weight:inherit;padding:.5em 1.9em .5em .5em;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0!important;-webkit-tap-highlight-color:transparent;width:100%}.emby-select[disabled]{background:0 0!important;border-color:transparent!important;color:inherit!important;-webkit-appearance:none;-moz-appearance:none;appearance:none}.selectContainer-inline>.emby-select{padding:.3em 1.9em .3em .5em;font-size:inherit}.selectContainer-inline>.emby-select[disabled]{padding:.4em 0}.emby-select::-moz-focus-inner{border:0}.emby-select-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.emby-select-focusscale:focus{-webkit-transform:scale(1.08);transform:scale(1.08);z-index:1}.emby-select+.fieldDescription{margin-top:.25em}.selectContainer{margin-bottom:1.8em;position:relative}.selectContainer-inline{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;margin-bottom:0;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.selectLabel{display:block;margin-bottom:.25em}.selectContainer-inline>.selectLabel{margin-bottom:0;margin-right:.5em;-webkit-flex-shrink:0;flex-shrink:0}.emby-select-withcolor{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-border-radius:.2em;border-radius:.2em}.selectArrowContainer{position:absolute;right:.3em;top:.27em;color:inherit;pointer-events:none}.selectContainer-inline>.selectArrowContainer{top:initial;bottom:.24em;font-size:90%}.emby-select[disabled]+.selectArrowContainer{display:none}.selectArrow{margin-top:.35em;font-size:1.7em}.emby-select-iconbutton{-webkit-align-self:flex-end;align-self:flex-end} \ No newline at end of file +.emby-select{display:block;margin:0;margin-bottom:0!important;font-size:110%;font-family:inherit;font-weight:inherit;padding:.5em 1.9em .5em .5em;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0!important;-webkit-tap-highlight-color:transparent;width:100%}.emby-select[disabled]{background:0 0!important;border-color:transparent!important;color:inherit!important;-webkit-appearance:none;-moz-appearance:none;appearance:none}.selectContainer-inline>.emby-select{padding:.3em 1.9em .3em .5em;font-size:inherit}.selectContainer-inline>.emby-select[disabled]{padding:.4em 0}.emby-select::-moz-focus-inner{border:0}.emby-select-focusscale{-webkit-transition:-webkit-transform 180ms ease-out!important;-o-transition:transform 180ms ease-out!important;transition:transform 180ms ease-out!important;-webkit-transform-origin:center center;transform-origin:center center}.emby-select-focusscale:focus{-webkit-transform:scale(1.04);transform:scale(1.04);z-index:1}.emby-select+.fieldDescription{margin-top:.25em}.selectContainer{margin-bottom:1.8em;position:relative}.selectContainer-inline{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;margin-bottom:0;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.selectLabel{display:block;margin-bottom:.25em}.selectContainer-inline>.selectLabel{margin-bottom:0;margin-right:.5em;-webkit-flex-shrink:0;flex-shrink:0}.emby-select-withcolor{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-border-radius:.2em;border-radius:.2em}.selectArrowContainer{position:absolute;right:.3em;top:.27em;color:inherit;pointer-events:none}.selectContainer-inline>.selectArrowContainer{top:initial;bottom:.24em;font-size:90%}.emby-select[disabled]+.selectArrowContainer{display:none}.selectArrow{margin-top:.35em;font-size:1.7em}.emby-select-iconbutton{-webkit-align-self:flex-end;align-self:flex-end} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fonts/fonts.css b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fonts/fonts.css index bc6bc394ab..e099b369dc 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fonts/fonts.css +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/fonts/fonts.css @@ -1 +1 @@ -h1,h2,h3{font-weight:500}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",'Open Sans',sans-serif;font-size:90%}h1{font-size:1.8em}.layout-desktop h1{font-size:2em}h2{font-size:1.5em}h3{font-size:1.17em}.layout-tv{font-size:2.5vh} \ No newline at end of file +h1,h2,h3{font-weight:500}html{font-family:-apple-system,Helvetica,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",'Open Sans',sans-serif;font-size:90%}h1{font-size:1.8em}.layout-desktop h1{font-size:2em}h2{font-size:1.5em}h3{font-size:1.17em}.layout-tv{font-size:2.5vh} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css index af6dce73a9..762094bfa0 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css @@ -1 +1 @@ -.tvGuideHeader,.tvguide{display:-webkit-box;display:-webkit-flex}.channelPrograms,.programContainer,.timeslotHeadersInner,.tvProgram{position:relative}.channelPrograms,.channelsContainer,.tvGuideHeader,.tvguide{-webkit-box-orient:vertical;-webkit-box-direction:normal}.guideChannelName,.guideChannelNumber,.guideProgramName,.guideProgramNameText{-o-text-overflow:ellipsis}.tvguide{display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-box-align:initial;-webkit-align-items:initial;align-items:initial}.tvGuideHeader{white-space:nowrap;width:100%;-webkit-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;flex-shrink:0;display:flex;contain:layout style paint}.layout-desktop .tvGuideHeader{margin-bottom:.5em}.guideHeaderDateSelection{font-size:86%;padding:.4em 0}.guide-headerTimeslots{display:-webkit-box;display:-webkit-flex;display:flex}.tvProgramSectionHeader{margin:0}.tvProgram{display:block;text-decoration:none;white-space:nowrap}.guideProgramIndicator{text-transform:uppercase;-webkit-border-radius:.25em;border-radius:.25em;margin-right:.5em;font-size:78%;padding:.08em .25em;display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;text-align:center;margin-left:1em}.guide-channelTimeslotHeader{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.timeslotHeaders{white-space:nowrap;font-weight:500;font-size:120%}.programContainer{white-space:nowrap;-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;contain:strict}.guideSpacer{width:.3em;-webkit-flex-shrink:0;flex-shrink:0}.channelPrograms,.timeslotHeadersInner{width:1800vw}@media all and (min-width:37.5em){.channelPrograms,.timeslotHeadersInner{width:1400vw}}@media all and (min-width:50em){.channelPrograms,.timeslotHeadersInner{width:1200vw}}@media all and (min-width:80em){.channelPrograms,.timeslotHeadersInner{width:810vw}}.timeslotHeader{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-indent:.25em;width:2.0833333333333333333333333333333%}.guide-channelHeaderCell,.guide-channelTimeslotHeader,.programCell{color:inherit;cursor:pointer;vertical-align:middle;font-family:inherit;text-decoration:none;-webkit-box-align:center;text-align:left;overflow:hidden}.guide-channelHeaderCell,.guide-channelTimeslotHeader{padding:0!important;outline:0!important;width:100%;font-size:inherit;-o-text-overflow:ellipsis;text-overflow:ellipsis;margin:0 1px 0 0;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;contain:strict;-webkit-flex-shrink:0;flex-shrink:0;-webkit-border-radius:.12em;border-radius:.12em}.guide-channelHeaderCell{border-width:1px 1px 1px 0;border-style:solid;width:100%;height:4.42em;contain:strict;position:relative;background:0 0}.guide-channelTimeslotHeader{border:0!important;border-right-color:transparent}.channelsContainer,.guide-channelTimeslotHeader{width:24vw}@media all and (min-width:31.25em){.channelsContainer,.guide-channelTimeslotHeader{width:16vw}}@media all and (min-width:37.5em){.channelsContainer,.guide-channelTimeslotHeader{width:16vw}}@media all and (min-width:50em){.channelsContainer,.guide-channelTimeslotHeader{width:14vw}}@media all and (min-width:80em){.channelsContainer,.guide-channelTimeslotHeader{width:12vw}}.btnGuideViewSettings{margin:0;-webkit-flex-shrink:0;flex-shrink:0}.btnGuideViewSettingsIcon{font-size:1.5em!important}.selectDateIcon{-webkit-flex-shrink:0;flex-shrink:0}@media all and (max-width:50em){.guideHdIcon,.liveTvProgram,.newTvProgram,.premiereTvProgram{display:none}}.channelPrograms,.programCell{border-style:solid;display:-webkit-box;display:-webkit-flex;contain:strict}.channelPrograms{white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;height:4.42em;display:flex;-webkit-flex-direction:column;flex-direction:column;border-width:1px 0}.channelPrograms+.channelPrograms,.guide-channelHeaderCell+.guide-channelHeaderCell{margin-top:-1px}.channelPrograms-tv,.guide-channelHeaderCell-tv{height:3em}.guide-channelTimeslotHeader,.timeslotHeader{background:0 0!important;height:2.8em}.programGrid{padding-bottom:4px;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.programCell{background:0 0;border-width:0 0 0 1px;padding:0!important;width:100%;font-size:inherit;position:absolute;top:0;bottom:0;display:flex;-webkit-align-items:center;align-items:center;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;margin:0!important}.channelsContainer,.guideProgramName,.programGrid{contain:layout style paint}.guide-programNameCaret,.guideProgramName{display:-webkit-box;display:-webkit-flex;-webkit-box-align:center}.guideProgramName{padding:0 .7em;overflow:hidden;text-overflow:ellipsis;-webkit-align-items:center;align-items:center;display:flex;position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.guide-programNameCaret{display:flex;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;font-size:200%}.guideProgramNameText{margin:0;font-weight:400;overflow:hidden;text-overflow:ellipsis}.guideProgramSecondaryInfo{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin-top:.1em}.programIcon{margin-left:.5em;height:1em;width:1em;font-size:1.6em;color:#ddd;-webkit-flex-shrink:0;flex-shrink:0;-webkit-box-flex:0;-webkit-flex-grow:0;flex-grow:0}.guide-programTextIcon{font-weight:700;font-size:.9em;padding:.16em .3em;-webkit-border-radius:.25em;border-radius:.25em;margin-right:.35em;width:auto;height:auto}.guide-programTextIcon-tv{font-size:.74em}.guideChannelNumber{padding-left:1em;max-width:30%;text-overflow:ellipsis;overflow:hidden;font-weight:400;margin:0}.guideChannelName{margin-left:auto;margin-right:1em;text-overflow:ellipsis;overflow:hidden;max-width:70%}.guideChannelImage{position:absolute;right:8%;top:15%;bottom:15%;width:40%;-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:right center}@media all and (min-width:62.5em){.guideChannelName{max-width:40%}}@media all and (max-width:62.5em){.guideChannelNumber{display:none}.guideChannelImage{width:70%}}.channelsContainer{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-shrink:0;flex-shrink:0;-webkit-flex-direction:column;flex-direction:column}.guide-channelHeaderCell,.programCell{outline:0!important}.seriesTimerIcon,.timerIcon{color:#c33!important}.seriesTimerIcon-inactive{color:inherit!important;opacity:.7}.guideOptions{-webkit-flex-shrink:0;flex-shrink:0;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}@media all and (max-width:50em),all and (max-height:37.5em){.tvGuideHeader{padding-left:0}}.guideRequiresUnlock{margin:1em auto;text-align:center;padding:1em;-webkit-flex-shrink:0;flex-shrink:0}.noRubberBanding{padding-bottom:100px}.guideDateTabsSlider{text-align:center}.guide-date-tab-button{padding:.3em .7em!important;margin:0 .3em!important;font-weight:400}.guide-date-tab-button.emby-tab-button-active{border-color:transparent!important}.guide-date-tab-button.emby-button-tv:focus{-webkit-border-radius:.15em!important;border-radius:.15em!important;-webkit-transform:none!important;transform:none!important} \ No newline at end of file +.tvGuideHeader,.tvguide{display:-webkit-box;display:-webkit-flex}.channelPrograms,.programContainer,.timeslotHeadersInner,.tvProgram{position:relative}.channelPrograms,.channelsContainer,.tvGuideHeader,.tvguide{-webkit-box-orient:vertical;-webkit-box-direction:normal}.guideChannelName,.guideChannelNumber,.guideProgramName,.guideProgramNameText{-o-text-overflow:ellipsis}.tvguide{display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-box-align:initial;-webkit-align-items:initial;align-items:initial}.tvGuideHeader{white-space:nowrap;width:100%;-webkit-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;flex-shrink:0;display:flex;contain:layout style paint}.layout-desktop .tvGuideHeader{margin-bottom:.5em}.guideHeaderDateSelection{font-size:86%;padding:.4em 0}.guide-headerTimeslots{display:-webkit-box;display:-webkit-flex;display:flex}.tvProgramSectionHeader{margin:0}.tvProgram{display:block;text-decoration:none;white-space:nowrap}.guideProgramIndicator{text-transform:uppercase;-webkit-border-radius:.25em;border-radius:.25em;margin-right:.5em;font-size:82%;padding:.2em .25em;display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;text-align:center;margin-left:1em}.guide-channelTimeslotHeader{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.timeslotHeaders{white-space:nowrap;font-weight:500;font-size:120%}.programContainer{white-space:nowrap;-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;contain:strict}.guideSpacer{width:.3em;-webkit-flex-shrink:0;flex-shrink:0}.channelPrograms,.timeslotHeadersInner{width:1800vw}@media all and (min-width:37.5em){.channelPrograms,.timeslotHeadersInner{width:1400vw}}@media all and (min-width:50em){.channelPrograms,.timeslotHeadersInner{width:1200vw}}@media all and (min-width:80em){.channelPrograms,.timeslotHeadersInner{width:810vw}}.timeslotHeader{display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-indent:.25em;width:2.0833333333333333333333333333333%}.guide-channelHeaderCell,.guide-channelTimeslotHeader,.programCell{color:inherit;cursor:pointer;vertical-align:middle;font-family:inherit;text-decoration:none;-webkit-box-align:center;text-align:left;overflow:hidden}.guide-channelHeaderCell,.guide-channelTimeslotHeader{padding:0!important;outline:0!important;width:100%;font-size:inherit;-o-text-overflow:ellipsis;text-overflow:ellipsis;margin:0 1px 0 0;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;contain:strict;-webkit-flex-shrink:0;flex-shrink:0;-webkit-border-radius:.12em;border-radius:.12em}.guide-channelHeaderCell{border-width:1px 1px 1px 0;border-style:solid;width:100%;height:4.42em;contain:strict;position:relative;background:0 0}.guide-channelTimeslotHeader{border:0!important;border-right-color:transparent}.channelsContainer,.guide-channelTimeslotHeader{width:24vw}@media all and (min-width:31.25em){.channelsContainer,.guide-channelTimeslotHeader{width:16vw}}@media all and (min-width:37.5em){.channelsContainer,.guide-channelTimeslotHeader{width:16vw}}@media all and (min-width:50em){.channelsContainer,.guide-channelTimeslotHeader{width:14vw}}@media all and (min-width:80em){.channelsContainer,.guide-channelTimeslotHeader{width:12vw}}.btnGuideViewSettings{margin:0;-webkit-flex-shrink:0;flex-shrink:0}.btnGuideViewSettingsIcon{font-size:1.5em!important}.selectDateIcon{-webkit-flex-shrink:0;flex-shrink:0}@media all and (max-width:50em){.guideHdIcon,.liveTvProgram,.newTvProgram,.premiereTvProgram{display:none}}.channelPrograms,.programCell{border-style:solid;display:-webkit-box;display:-webkit-flex;contain:strict}.channelPrograms{white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;height:4.42em;display:flex;-webkit-flex-direction:column;flex-direction:column;border-width:1px 0}.channelPrograms+.channelPrograms,.guide-channelHeaderCell+.guide-channelHeaderCell{margin-top:-1px}.channelPrograms-tv,.guide-channelHeaderCell-tv{height:3em}.guide-channelTimeslotHeader,.timeslotHeader{background:0 0!important;height:2.8em}.programGrid{padding-bottom:4px;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.programCell{background:0 0;border-width:0 0 0 1px;padding:0!important;width:100%;font-size:inherit;position:absolute;top:0;bottom:0;display:flex;-webkit-align-items:center;align-items:center;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;margin:0!important}.channelsContainer,.guideProgramName,.programGrid{contain:layout style paint}.guide-programNameCaret,.guideProgramName{display:-webkit-box;display:-webkit-flex;-webkit-box-align:center}.guideProgramName{padding:0 .7em;overflow:hidden;text-overflow:ellipsis;-webkit-align-items:center;align-items:center;display:flex;position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.guide-programNameCaret{display:flex;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;font-size:200%}.guideProgramNameText{margin:0;font-weight:400;overflow:hidden;text-overflow:ellipsis}.guideProgramSecondaryInfo{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;margin-top:.1em}.programIcon{margin-left:.5em;height:1em;width:1em;font-size:1.6em;color:#ddd;-webkit-flex-shrink:0;flex-shrink:0;-webkit-box-flex:0;-webkit-flex-grow:0;flex-grow:0}.guide-programTextIcon{font-weight:700;font-size:.9em;padding:.16em .3em;-webkit-border-radius:.25em;border-radius:.25em;margin-right:.35em;width:auto;height:auto}.guide-programTextIcon-tv{font-size:.74em}.guideChannelNumber{padding-left:1em;max-width:30%;text-overflow:ellipsis;overflow:hidden;font-weight:400;margin:0}.guideChannelName{margin-left:auto;margin-right:1em;text-overflow:ellipsis;overflow:hidden;max-width:70%}.guideChannelImage{position:absolute;right:8%;top:15%;bottom:15%;width:40%;-webkit-background-size:contain;background-size:contain;background-repeat:no-repeat;background-position:right center}@media all and (min-width:62.5em){.guideChannelName{max-width:40%}}@media all and (max-width:62.5em){.guideChannelNumber{display:none}.guideChannelImage{width:70%}}.channelsContainer{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-shrink:0;flex-shrink:0;-webkit-flex-direction:column;flex-direction:column}.guide-channelHeaderCell,.programCell{outline:0!important}.seriesTimerIcon,.timerIcon{color:#c33!important}.seriesTimerIcon-inactive{color:inherit!important;opacity:.7}.guideOptions{-webkit-flex-shrink:0;flex-shrink:0;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}@media all and (max-width:50em),all and (max-height:37.5em){.tvGuideHeader{padding-left:0}}.guideRequiresUnlock{margin:1em auto;text-align:center;padding:1em;-webkit-flex-shrink:0;flex-shrink:0}.noRubberBanding{padding-bottom:100px}.guideDateTabsSlider{text-align:center}.guide-date-tab-button{padding:.3em .7em!important;margin:0 .3em!important;font-weight:400}.guide-date-tab-button.emby-tab-button-active{border-color:transparent!important}.guide-date-tab-button.emby-button-tv:focus{-webkit-border-radius:.15em!important;border-radius:.15em!important;-webkit-transform:none!important;transform:none!important} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js index 1b5a75f4d1..3469ef2cb6 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js +++ b/MediaBrowser.WebDashboard/dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js @@ -1 +1 @@ -define(["visibleinviewport","dom","browser"],function(visibleinviewport,dom,browser){"use strict";function resetThresholds(){var threshold=(browser.iOS,.2);thresholdX=screen.availWidth*threshold,thresholdY=screen.availHeight*threshold}function resetThresholdsOnTimer(){setTimeout(resetThresholds,500)}function isVisible(elem){return visibleinviewport(elem,!0,thresholdX,thresholdY)}function cancelAll(tokens){for(var i=0,length=tokens.length;i=elements.length&&(dom.removeEventListener(document,"focus",unveil,{capture:!0,passive:!0}),dom.removeEventListener(document,"scroll",unveil,{capture:!0,passive:!0}),dom.removeEventListener(document,wheelEvent,unveil,{capture:!0,passive:!0}),dom.removeEventListener(window,"resize",unveil,{capture:!0,passive:!0}))}function unveil(){cancelAll(cancellationTokens);var index=cancellationTokens.length;cancellationTokens.length++,setTimeout(function(){unveilInternal(index)},1)}var unveiledElements=[],cancellationTokens=[],loadedCount=0;dom.addEventListener(document,"focus",unveil,{capture:!0,passive:!0}),dom.addEventListener(document,"scroll",unveil,{capture:!0,passive:!0}),dom.addEventListener(document,wheelEvent,unveil,{capture:!0,passive:!0}),dom.addEventListener(window,"resize",unveil,{capture:!0,passive:!0}),unveil()}function LazyLoader(options){this.options=options}function unveilElements(elements,root,callback){if(elements.length){new LazyLoader({callback:callback}).addElements(elements)}}var thresholdX,thresholdY;window.requestIdleCallback;browser.iOS?(dom.addEventListener(window,"orientationchange",resetThresholdsOnTimer,{passive:!0}),dom.addEventListener(window,"resize",resetThresholdsOnTimer,{passive:!0})):(dom.addEventListener(window,"orientationchange",resetThresholds,{passive:!0}),dom.addEventListener(window,"resize",resetThresholds,{passive:!0})),resetThresholds();var wheelEvent=document.implementation.hasFeature("Event.wheel","3.0")?"wheel":"mousewheel";return LazyLoader.prototype.createObserver=function(){unveilElementsInternal(this,this.options.callback),this.observer=1},LazyLoader.prototype.addElements=function(elements){this.elements=this.elements||[];for(var i=0,length=elements.length;i=elements.length&&(dom.removeEventListener(document,"focus",unveil,{capture:!0,passive:!0}),dom.removeEventListener(document,"scroll",unveil,{capture:!0,passive:!0}),dom.removeEventListener(document,wheelEvent,unveil,{capture:!0,passive:!0}),dom.removeEventListener(window,"resize",unveil,{capture:!0,passive:!0}))}function unveil(){cancelAll(cancellationTokens);var index=cancellationTokens.length;cancellationTokens.length++,setTimeout(function(){unveilInternal(index)},1)}var unveiledElements=[],cancellationTokens=[],loadedCount=0;dom.addEventListener(document,"focus",unveil,{capture:!0,passive:!0}),dom.addEventListener(document,"scroll",unveil,{capture:!0,passive:!0}),dom.addEventListener(document,wheelEvent,unveil,{capture:!0,passive:!0}),dom.addEventListener(window,"resize",unveil,{capture:!0,passive:!0}),unveil()}function LazyLoader(options){this.options=options}function unveilElements(elements,root,callback){if(elements.length){new LazyLoader({callback:callback}).addElements(elements)}}var thresholdX,thresholdY;window.requestIdleCallback;browser.iOS?(dom.addEventListener(window,"orientationchange",resetThresholdsOnTimer,{passive:!0}),dom.addEventListener(window,"resize",resetThresholdsOnTimer,{passive:!0})):(dom.addEventListener(window,"orientationchange",resetThresholds,{passive:!0}),dom.addEventListener(window,"resize",resetThresholds,{passive:!0})),resetThresholds();var wheelEvent=document.implementation.hasFeature("Event.wheel","3.0")?"wheel":"mousewheel";return LazyLoader.prototype.createObserver=function(){unveilElementsInternal(this,this.options.callback),this.observer=1},LazyLoader.prototype.addElements=function(elements){this.elements=this.elements||[];for(var i=0,length=elements.length;ioption{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:#1c1c1f;color:#ccc;color:rgba(255,255,255,.7)}.navMenuDivider{background:#202020;background:rgba(255,255,255,.12)}.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:#383838}.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(#191919));background:-webkit-linear-gradient(rgba(0,0,0,0),#191919);background:-o-linear-gradient(rgba(0,0,0,0),#191919);background:linear-gradient(rgba(0,0,0,0),#191919)}@media all and (min-width:62.5em){.detailButton-mobile{background:#444!important}.detailTrackSelect.emby-select-withcolor{background:#444;border-color:#444}}.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} \ No newline at end of file +html{color:#eee;color:rgba(255,255,255,.87)}.emby-collapsible-button{border-color:#383838;border-color:rgba(255,255,255,.135)}.skinHeader{color:#ccc;color:rgba(255,255,255,.78)}.skinHeader-withBackground{background-color:#1c1c1c;-webkit-box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37);box-shadow:0 .0725em .29em 0 rgba(0,0,0,.37)}.osdHeader{-webkit-box-shadow:none!important;box-shadow:none!important}.skinHeader.semiTransparent{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));-webkit-box-shadow:none;box-shadow:none}.pageTitleWithDefaultLogo{background-image:url(../logowhite.png)}.backgroundContainer,.dialog{background-color:#282828}.backgroundContainer.withBackdrop{background-color:rgba(12,12,12,.9)}.paper-icon-button-light:focus{color:#52B54B}.fab,.raised{background:#404040;color:#fff}.button-accent,.button-submit{background:#52B54B;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:#222}.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:#222}.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),.listItem-shaded:nth-child(even){background:#1c1c1c;background:rgba(30,30,30,.9)}.listItem-border{border-color:rgba(30,30,30,.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:#1c1c1c;border:.07em solid #1c1c1c;-webkit-border-radius:.15em;border-radius:.15em}.emby-input:focus,.emby-textarea:focus{border-color:#52B54B}.emby-select-withcolor{color:inherit;background:#1c1c1c;border:.07em solid #1c1c1c}.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:#1c1c1f;color:#ccc;color:rgba(255,255,255,.7)}.navMenuDivider{background:#202020;background:rgba(255,255,255,.12)}.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:#383838}.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(#191919));background:-webkit-linear-gradient(rgba(0,0,0,0),#191919);background:-o-linear-gradient(rgba(0,0,0,0),#191919);background:linear-gradient(rgba(0,0,0,0),#191919)}@media all and (min-width:62.5em){.detailButton-mobile{background:#444!important}.detailTrackSelect.emby-select-withcolor{background:#444;border-color:#444}}.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} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css b/MediaBrowser.WebDashboard/dashboard-ui/css/librarybrowser.css index b7df5e0fe7..9806382727 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:6em!important}.itemDetailPage{padding-top:4em!important}.standalonePage{padding-top:5.5em!important}.wizardPage{padding-top:7em!important}.libraryPage:not(.noSecondaryNavPage){padding-top:9.2em!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}.navMenuDivider{height:1px;margin:.5em 0;display:none}.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;font-size:108%}.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}.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:-webkit-box;display:-webkit-flex;display:flex;flex-direction:column;background-color:#121212;color:#ccc;contain:layout style paint}.mainAnimatedPages,.pageTabContent{contain:layout style}.hiddenViewMenuBar .skinHeader{display:none}.headerLeft,.headerRight{display:-webkit-box;display:-webkit-flex;-webkit-box-align:center}.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: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;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-decoration:none;color:inherit;padding:.9em 0 .9em 2.4em;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.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}@media all and (max-width:40em){.navMenuOption{font-size:110%}}.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.07em!important;font-size:92%}.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.1em}.libraryPage:not(.noSecondaryNavPage){padding-top:6.3em!important}.pageWithAbsoluteTabs:not(.noSecondaryNavPage){padding-top:8.4em!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}.mainDetailButtons>.raised{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.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-top:.5em!important;padding-bottom:.5em!important}@media all and (min-width:29em){.detailButton-mobile{margin-right:.1em!important}}@media all and (min-width:32em){.detailButton-mobile{margin-right:.2em!important}}@media all and (min-width:35em){.detailButton-mobile{margin-right:.3em!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}@media all and (max-width:62.5em){.detailButton-mobile-text{margin-top:.7em;font-size:80%;font-weight:400}.mainDetailButtons{margin-left:-.5em}}@media all and (min-width:62.5em){.detailButton-mobile-icon:not(.always),.detailButton-mobile-text.texthide{display:none!important}.detailButton-mobile{padding-top:0!important;padding-bottom:0!important;height:3em}.mainDetailButtons{font-size:108%;margin:1.25em 0}.detailButton-mobile-icon:not(.notext){margin-right:.25em}.detailButton-mobile-icon.playstatebutton-icon-unplayed{opacity:.2}.detailButton-mobile-content{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}.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}}.mediaInfoContent{line-height:1.5em}.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}.sectionTitleButton,.sectionTitleIconButton{margin-right:0!important;display:inline-block;vertical-align:middle}.verticalSection{margin-bottom:1em}@media all and (max-width:500px),(max-height:720px){.verticalSection{margin-bottom:1em}}.verticalSection-extrabottompadding{margin-bottom:2.7em}.sectionTitleContainer{margin-bottom:.5em}.sectionTitle{margin-bottom:1em}.sectionTitle-cards{margin-bottom:.3em}.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;color:#aaa!important;font-size:84%!important;padding:.5em!important}.sectionTitle-cards{margin-left:.12em;margin-top:0}.layout-tv .sectionTitle-cards{margin-left:.3em;margin-bottom:.2em}.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}.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-height:500px) and (min-width:400px){.padded-left-withalphapicker{padding-left:7%}.padded-right-withalphapicker{padding-right:7%}}@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.6%}.padded-right{padding-right:3.6%}}@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}@media all and (min-width:40em){.listIconButton-autohide{display:none!important}}@media all and (max-width:40em){.listTextButton-autohide{display:none!important}} \ 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:6em!important}.itemDetailPage{padding-top:4em!important}.standalonePage{padding-top:5.5em!important}.wizardPage{padding-top:7em!important}.libraryPage:not(.noSecondaryNavPage){padding-top:9.2em!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}.navMenuDivider{height:1px;margin:.5em 0;display:none}.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;font-size:108%}.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}.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:-webkit-box;display:-webkit-flex;display:flex;flex-direction:column;background-color:#121212;color:#ccc;contain:layout style paint}.mainAnimatedPages,.pageTabContent{contain:layout style}.hiddenViewMenuBar .skinHeader{display:none}.headerLeft,.headerRight{display:-webkit-box;display:-webkit-flex;-webkit-box-align:center}.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: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;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-decoration:none;color:inherit;padding:.9em 0 .9em 2.4em;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.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}@media all and (max-width:40em){.navMenuOption{font-size:110%}}.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.07em!important;font-size:92%}.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:-1em}.libraryPage:not(.noSecondaryNavPage){padding-top:6.3em!important}.pageWithAbsoluteTabs:not(.noSecondaryNavPage){padding-top:8.4em!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}.mainDetailButtons>.raised{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.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-top:.5em!important;padding-bottom:.5em!important}@media all and (min-width:29em){.detailButton-mobile{margin-right:.1em!important}}@media all and (min-width:32em){.detailButton-mobile{margin-right:.2em!important}}@media all and (min-width:35em){.detailButton-mobile{margin-right:.3em!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}@media all and (max-width:62.5em){.detailButton-mobile-text{margin-top:.7em;font-size:80%;font-weight:400}.mainDetailButtons{margin-left:-.5em}}@media all and (min-width:62.5em){.detailButton-mobile-icon:not(.always),.detailButton-mobile-text.texthide{display:none!important}.detailButton-mobile{padding-top:0!important;padding-bottom:0!important;height:3em}.mainDetailButtons{font-size:108%;margin:1.25em 0}.detailButton-mobile-icon:not(.notext){margin-right:.25em}.detailButton-mobile-icon.playstatebutton-icon-unplayed{opacity:.2}.detailButton-mobile-content{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}.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}}.mediaInfoContent{line-height:1.5em}.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}.sectionTitleButton,.sectionTitleIconButton{margin-right:0!important;display:inline-block;vertical-align:middle}.verticalSection{margin-bottom:1.7em}@media all and (max-width:500px),(max-height:720px){.verticalSection{margin-bottom:1em}}.verticalSection-extrabottompadding{margin-bottom:2.7em}.sectionTitleContainer{margin-bottom:.4em}.sectionTitle{margin-bottom:1em}.sectionTitle-cards{margin-bottom:.3em;margin-left:.16em;margin-top:0}.layout-tv .sectionTitle-cards{margin-left:.4em;margin-bottom:.1em}.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;color:#aaa!important;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}.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-height:500px) and (min-width:400px){.padded-left-withalphapicker{padding-left:7%}.padded-right-withalphapicker{padding-right:7%}}@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}@media all and (min-width:40em){.listIconButton-autohide{display:none!important}}@media all and (max-width:40em){.listTextButton-autohide{display:none!important}} \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/livetvstatus.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/livetvstatus.js index 871e604918..788afc3053 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/livetvstatus.js +++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/livetvstatus.js @@ -1 +1 @@ -define(["jQuery","globalize","scripts/taskbutton","dom","libraryMenu","layoutManager","loading","listViewStyle","flexStyles","emby-itemscontainer","cardStyle","material-icons","emby-linkbutton"],function($,globalize,taskButton,dom,libraryMenu,layoutManager,loading){"use strict";function getDeviceHtml(device){var padderClass,html="",cssClass="card scalableCard",cardBoxCssClass="cardBox visualCardBox";return cssClass+=" backdropCard backdropCard-scalable",padderClass="cardPadder-backdrop",layoutManager.tv&&(cssClass+=" card-focusscale",cardBoxCssClass+=" cardBox-focustransform"),cardBoxCssClass+=" card-focuscontent",html+='
',html+='
',html+='
',html+='
',html+='
',html+='
dvr
',html+="
",html+="
",html+='
',html+='',html+='
'+(device.FriendlyName||getTunerName(device.Type))+"
",html+='
',html+=device.Url||" ",html+="
",html+="
",html+="
",html+="
"}function renderDevices(page,devices){var html=devices.map(getDeviceHtml).join("");page.querySelector(".devicesList").innerHTML=html}function deleteDevice(page,id){var message=globalize.translate("MessageConfirmDeleteTunerDevice");require(["confirm"],function(confirm){confirm(message,globalize.translate("HeaderDeleteDevice")).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("LiveTv/TunerHosts",{Id:id})}).then(function(){reload(page)})})})}function reload(page){loading.show(),ApiClient.getNamedConfiguration("livetv").then(function(config){renderDevices(page,config.TunerHosts),renderProviders(page,config.ListingProviders)}),loading.hide()}function submitAddDeviceForm(page){page.querySelector(".dlgAddDevice").close(),loading.show(),ApiClient.ajax({type:"POST",url:ApiClient.getUrl("LiveTv/TunerHosts"),data:JSON.stringify({Type:$("#selectTunerDeviceType",page).val(),Url:$("#txtDevicePath",page).val()}),contentType:"application/json"}).then(function(){reload(page)},function(){Dashboard.alert({message:globalize.translate("ErrorAddingTunerDevice")})})}function renderProviders(page,providers){var html="";if(providers.length){html+='
';for(var i=0,length=providers.length;i',html+='dvr',html+='",html+='',html+="
"}html+=""}var elem=$(".providerList",page).html(html);$(".btnOptions",elem).on("click",function(){var id=this.getAttribute("data-id");showProviderOptions(page,id,this)})}function showProviderOptions(page,providerId,button){var items=[];items.push({name:globalize.translate("ButtonDelete"),id:"delete"}),items.push({name:globalize.translate("MapChannels"),id:"map"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:items,positionTo:button}).then(function(id){switch(id){case"delete":deleteProvider(page,providerId);break;case"map":mapChannels(page,providerId)}})})}function mapChannels(page,providerId){require(["components/channelmapper/channelmapper"],function(channelmapper){new channelmapper({serverId:ApiClient.serverInfo().Id,providerId:providerId}).show()})}function deleteProvider(page,id){var message=globalize.translate("MessageConfirmDeleteGuideProvider");require(["confirm"],function(confirm){confirm(message,globalize.translate("HeaderDeleteProvider")).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("LiveTv/ListingProviders",{Id:id})}).then(function(){reload(page)},function(){reload(page)})})})}function getTunerName(providerId){switch(providerId=providerId.toLowerCase()){case"m3u":return"M3U";case"hdhomerun":return"HDHomerun";case"hauppauge":return"Hauppauge";case"satip":return"DVB";default:return"Unknown"}}function getProviderName(providerId){switch(providerId=providerId.toLowerCase()){case"schedulesdirect":return"Schedules Direct";case"xmltv":return"Xml TV";case"emby":return"Emby Guide";default:return"Unknown"}}function getProviderConfigurationUrl(providerId){switch(providerId=providerId.toLowerCase()){case"xmltv":return"livetvguideprovider.html?type=xmltv";case"schedulesdirect":return"livetvguideprovider.html?type=schedulesdirect";case"emby":return"livetvguideprovider.html?type=emby"}}function addProvider(button){var menuItems=[];menuItems.push({name:"Schedules Direct",id:"SchedulesDirect"}),menuItems.push({name:"Xml TV",id:"xmltv"}),menuItems.push({name:globalize.translate("ButtonOther"),id:"other"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:menuItems,positionTo:button,callback:function(id){"other"==id?Dashboard.alert({message:globalize.translate("ForAdditionalLiveTvOptions")}):Dashboard.navigate(getProviderConfigurationUrl(id))}})})}function addDevice(button){Dashboard.navigate("livetvtuner.html")}function getTabs(){return[{href:"livetvstatus.html",name:globalize.translate("TabDevices")},{href:"appservices.html?context=livetv",name:globalize.translate("TabServices")}]}function showDeviceMenu(button,tunerDeviceId){var items=[];items.push({name:globalize.translate("ButtonDelete"),id:"delete"}),items.push({name:globalize.translate("ButtonEdit"),id:"edit"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:items,positionTo:button}).then(function(id){switch(id){case"delete":deleteDevice(dom.parentWithClass(button,"page"),tunerDeviceId);break;case"edit":Dashboard.navigate("livetvtuner.html?id="+tunerDeviceId)}})})}function onDevicesListClick(e){var card=dom.parentWithClass(e.target,"card");if(card){var id=card.getAttribute("data-id"),btnCardOptions=dom.parentWithClass(e.target,"btnCardOptions");btnCardOptions?showDeviceMenu(btnCardOptions,id):Dashboard.navigate("livetvtuner.html?id="+id)}}$(document).on("pageinit","#liveTvStatusPage",function(){var page=this;$(".btnAddDevice",page).on("click",function(){addDevice(this)}),$(".formAddDevice",page).on("submit",function(){return submitAddDeviceForm(page),!1}),$(".btnAddProvider",page).on("click",function(){addProvider(this)}),page.querySelector(".devicesList").addEventListener("click",onDevicesListClick)}).on("pageshow","#liveTvStatusPage",function(){libraryMenu.setTabs("livetvadmin",0,getTabs);var page=this;reload(page),taskButton({mode:"on",progressElem:page.querySelector(".refreshGuideProgress"),taskKey:"RefreshGuide",button:page.querySelector(".btnRefresh")})}).on("pagehide","#liveTvStatusPage",function(){var page=this;taskButton({mode:"off",progressElem:page.querySelector(".refreshGuideProgress"),taskKey:"RefreshGuide",button:page.querySelector(".btnRefresh")})})}); \ No newline at end of file +define(["jQuery","globalize","scripts/taskbutton","dom","libraryMenu","layoutManager","loading","listViewStyle","flexStyles","emby-itemscontainer","cardStyle","material-icons","emby-linkbutton"],function($,globalize,taskButton,dom,libraryMenu,layoutManager,loading){"use strict";function getDeviceHtml(device){var padderClass,html="",cssClass="card scalableCard",cardBoxCssClass="cardBox visualCardBox";return cssClass+=" backdropCard backdropCard-scalable",padderClass="cardPadder-backdrop",layoutManager.tv&&(cssClass+=" card-focusscale",cardBoxCssClass+=" cardBox-focustransform"),cardBoxCssClass+=" card-focuscontent",html+='
',html+='
',html+='
',html+='
',html+='
',html+='
dvr
',html+="
",html+="
",html+='
',html+='',html+='
'+(device.FriendlyName||getTunerName(device.Type))+"
",html+='
',html+=device.Url||" ",html+="
",html+="
",html+="
",html+="
"}function renderDevices(page,devices){var html=devices.map(getDeviceHtml).join("");page.querySelector(".devicesList").innerHTML=html}function deleteDevice(page,id){var message=globalize.translate("MessageConfirmDeleteTunerDevice");require(["confirm"],function(confirm){confirm(message,globalize.translate("HeaderDeleteDevice")).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("LiveTv/TunerHosts",{Id:id})}).then(function(){reload(page)})})})}function reload(page){loading.show(),ApiClient.getNamedConfiguration("livetv").then(function(config){renderDevices(page,config.TunerHosts),renderProviders(page,config.ListingProviders)}),loading.hide()}function submitAddDeviceForm(page){page.querySelector(".dlgAddDevice").close(),loading.show(),ApiClient.ajax({type:"POST",url:ApiClient.getUrl("LiveTv/TunerHosts"),data:JSON.stringify({Type:$("#selectTunerDeviceType",page).val(),Url:$("#txtDevicePath",page).val()}),contentType:"application/json"}).then(function(){reload(page)},function(){Dashboard.alert({message:globalize.translate("ErrorAddingTunerDevice")})})}function renderProviders(page,providers){var html="";if(providers.length){html+='
';for(var i=0,length=providers.length;i',html+='dvr',html+='",html+='',html+="
"}html+=""}var elem=$(".providerList",page).html(html);$(".btnOptions",elem).on("click",function(){var id=this.getAttribute("data-id");showProviderOptions(page,id,this)})}function showProviderOptions(page,providerId,button){var items=[];items.push({name:globalize.translate("ButtonDelete"),id:"delete"}),items.push({name:globalize.translate("MapChannels"),id:"map"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:items,positionTo:button}).then(function(id){switch(id){case"delete":deleteProvider(page,providerId);break;case"map":mapChannels(page,providerId)}})})}function mapChannels(page,providerId){require(["components/channelmapper/channelmapper"],function(channelmapper){new channelmapper({serverId:ApiClient.serverInfo().Id,providerId:providerId}).show()})}function deleteProvider(page,id){var message=globalize.translate("MessageConfirmDeleteGuideProvider");require(["confirm"],function(confirm){confirm(message,globalize.translate("HeaderDeleteProvider")).then(function(){loading.show(),ApiClient.ajax({type:"DELETE",url:ApiClient.getUrl("LiveTv/ListingProviders",{Id:id})}).then(function(){reload(page)},function(){reload(page)})})})}function getTunerName(providerId){switch(providerId=providerId.toLowerCase()){case"m3u":return"M3U";case"hdhomerun":return"HDHomerun";case"hauppauge":return"Hauppauge";case"satip":return"DVB";default:return"Unknown"}}function getProviderName(providerId){switch(providerId=providerId.toLowerCase()){case"schedulesdirect":return"Schedules Direct";case"xmltv":return"Xml TV";case"emby":return"Emby Guide";default:return"Unknown"}}function getProviderConfigurationUrl(providerId){switch(providerId=providerId.toLowerCase()){case"xmltv":return"livetvguideprovider.html?type=xmltv";case"schedulesdirect":return"livetvguideprovider.html?type=schedulesdirect";case"emby":return"livetvguideprovider.html?type=emby"}}function addProvider(button){var menuItems=[];menuItems.push({name:"Schedules Direct",id:"SchedulesDirect"}),menuItems.push({name:"Xml TV",id:"xmltv"}),menuItems.push({name:globalize.translate("ButtonOther"),id:"other"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:menuItems,positionTo:button,callback:function(id){"other"==id?Dashboard.alert({message:globalize.translate("ForAdditionalLiveTvOptions")}):Dashboard.navigate(getProviderConfigurationUrl(id))}})})}function addDevice(button){Dashboard.navigate("livetvtuner.html")}function getTabs(){return[{href:"livetvstatus.html",name:globalize.translate("TabDevices")},{href:"appservices.html?context=livetv",name:globalize.translate("TabServices")}]}function showDeviceMenu(button,tunerDeviceId){var items=[];items.push({name:globalize.translate("ButtonDelete"),id:"delete"}),items.push({name:globalize.translate("ButtonEdit"),id:"edit"}),require(["actionsheet"],function(actionsheet){actionsheet.show({items:items,positionTo:button}).then(function(id){switch(id){case"delete":deleteDevice(dom.parentWithClass(button,"page"),tunerDeviceId);break;case"edit":Dashboard.navigate("livetvtuner.html?id="+tunerDeviceId)}})})}function onDevicesListClick(e){var card=dom.parentWithClass(e.target,"card");if(card){var id=card.getAttribute("data-id"),btnCardOptions=dom.parentWithClass(e.target,"btnCardOptions");btnCardOptions?showDeviceMenu(btnCardOptions,id):Dashboard.navigate("livetvtuner.html?id="+id)}}$(document).on("pageinit","#liveTvStatusPage",function(){var page=this;$(".btnAddDevice",page).on("click",function(){addDevice(this)}),$(".formAddDevice",page).on("submit",function(){return submitAddDeviceForm(page),!1}),$(".btnAddProvider",page).on("click",function(){addProvider(this)}),page.querySelector(".devicesList").addEventListener("click",onDevicesListClick)}).on("pageshow","#liveTvStatusPage",function(){libraryMenu.setTabs("livetvadmin",0,getTabs);var page=this;reload(page),taskButton({mode:"on",progressElem:page.querySelector(".refreshGuideProgress"),taskKey:"RefreshGuide",button:page.querySelector(".btnRefresh")})}).on("pagehide","#liveTvStatusPage",function(){var page=this;taskButton({mode:"off",progressElem:page.querySelector(".refreshGuideProgress"),taskKey:"RefreshGuide",button:page.querySelector(".btnRefresh")})})}); \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/dashboard-ui/scripts/movies.js b/MediaBrowser.WebDashboard/dashboard-ui/scripts/movies.js index fb8e0897ee..f1af581c28 100644 --- a/MediaBrowser.WebDashboard/dashboard-ui/scripts/movies.js +++ b/MediaBrowser.WebDashboard/dashboard-ui/scripts/movies.js @@ -1 +1 @@ -define(["layoutManager","userSettings","events","libraryBrowser","alphaPicker","listView","cardBuilder","emby-itemscontainer"],function(layoutManager,userSettings,events,libraryBrowser,alphaPicker,listView,cardBuilder){"use strict";return function(view,params,tabContent,options){function onViewStyleChange(){"List"==self.getCurrentViewStyle()?(itemsContainer.classList.add("vertical-list"),itemsContainer.classList.remove("vertical-wrap")):(itemsContainer.classList.remove("vertical-list"),itemsContainer.classList.add("vertical-wrap")),itemsContainer.innerHTML=""}function updateFilterControls(){self.alphaPicker&&self.alphaPicker.value(query.NameStartsWithOrGreater)}function fetchData(){return ApiClient.getItems(ApiClient.getCurrentUserId(),query)}function afterRefresh(result){function onNextPageClick(){query.StartIndex+=query.Limit,itemsContainer.refreshItems()}function onPreviousPageClick(){query.StartIndex-=query.Limit,itemsContainer.refreshItems()}updateFilterControls();var i,length,pagingHtml=libraryBrowser.getQueryPagingHtml({startIndex:query.StartIndex,limit:query.Limit,totalRecordCount:result.TotalRecordCount,showLimit:!1,updatePageSizeSetting:!1,addLayoutButton:!1,sortButton:!1,filterButton:!1}),elems=tabContent.querySelectorAll(".paging");for(i=0,length=elems.length;i prefixes; // Dictionary - List unhandled; // List unhandled; host = '*' - List all; // List all; host = '+' - X509Certificate cert; - bool secure; - Dictionary unregistered; - private readonly ILogger _logger; - private bool _closed; - private bool _enableDualMode; - private readonly ICryptoProvider _cryptoProvider; - private readonly ISocketFactory _socketFactory; - private readonly ITextEncoding _textEncoding; - private readonly IMemoryStreamFactory _memoryStreamFactory; - private readonly IFileSystem _fileSystem; - private readonly IEnvironmentInfo _environment; - - public EndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert, ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) - { - this.listener = listener; - _logger = logger; - _cryptoProvider = cryptoProvider; - _socketFactory = socketFactory; - _memoryStreamFactory = memoryStreamFactory; - _textEncoding = textEncoding; - _fileSystem = fileSystem; - _environment = environment; - - this.secure = secure; - this.cert = cert; - - _enableDualMode = addr.Equals(IPAddress.IPv6Any); - endpoint = new IPEndPoint(addr, port); - - prefixes = new Dictionary(); - unregistered = new Dictionary(); - - CreateSocket(); - } - - internal HttpListener Listener - { - get - { - return listener; - } - } - - private void CreateSocket() - { - try - { - sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode); - } - catch (SocketCreateException ex) - { - if (_enableDualMode && endpoint.Address.Equals(IPAddress.IPv6Any) && - (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || - // mono on bsd is throwing this - string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase))) - { - endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port); - _enableDualMode = false; - sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode); - } - else - { - throw; - } - } - - try - { - sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - catch (SocketException) - { - // This is not supported on all operating systems (qnap) - } - - sock.Bind(endpoint); - - // This is the number TcpListener uses. - sock.Listen(2147483647); - - new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept(); - _closed = false; - } - - private Socket CreateSocket(AddressFamily addressFamily, bool dualMode) - { - try - { - var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); - - if (dualMode) - { - socket.DualMode = true; - } - - return socket; - } - catch (SocketException ex) - { - throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex); - } - catch (ArgumentException ex) - { - if (dualMode) - { - // Mono for BSD incorrectly throws ArgumentException instead of SocketException - throw new SocketCreateException("AddressFamilyNotSupported", ex); - } - else - { - throw; - } - } - } - - private void ProcessAccept(Socket accepted) - { - try - { - var listener = this; - - if (listener.secure && listener.cert == null) - { - accepted.Close(); - return; - } - - HttpConnection conn = new HttpConnection(_logger, accepted, listener, secure, cert, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem, _environment); - - //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId); - lock (listener.unregistered) - { - listener.unregistered[conn] = conn; - } - conn.BeginReadRequest(); - } - catch (Exception ex) - { - _logger.ErrorException("Error in ProcessAccept", ex); - } - } - - internal void RemoveConnection(HttpConnection conn) - { - lock (unregistered) - { - unregistered.Remove(conn); - } - } - - public bool BindContext(HttpListenerContext context) - { - HttpListenerRequest req = context.Request; - ListenerPrefix prefix; - HttpListener listener = SearchListener(req.Url, out prefix); - if (listener == null) - return false; - - context.Connection.Prefix = prefix; - return true; - } - - public void UnbindContext(HttpListenerContext context) - { - if (context == null || context.Request == null) - return; - - listener.UnregisterContext(context); - } - - HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) - { - prefix = null; - if (uri == null) - return null; - - string host = uri.Host; - int port = uri.Port; - string path = WebUtility.UrlDecode(uri.AbsolutePath); - string path_slash = path[path.Length - 1] == '/' ? path : path + "/"; - - HttpListener best_match = null; - int best_length = -1; - - if (host != null && host != "") - { - var p_ro = prefixes; - foreach (ListenerPrefix p in p_ro.Keys) - { - string ppath = p.Path; - if (ppath.Length < best_length) - continue; - - if (p.Host != host || p.Port != port) - continue; - - if (path.StartsWith(ppath) || path_slash.StartsWith(ppath)) - { - best_length = ppath.Length; - best_match = (HttpListener)p_ro[p]; - prefix = p; - } - } - if (best_length != -1) - return best_match; - } - - List list = unhandled; - best_match = MatchFromList(host, path, list, out prefix); - if (path != path_slash && best_match == null) - best_match = MatchFromList(host, path_slash, list, out prefix); - if (best_match != null) - return best_match; - - list = all; - best_match = MatchFromList(host, path, list, out prefix); - if (path != path_slash && best_match == null) - best_match = MatchFromList(host, path_slash, list, out prefix); - if (best_match != null) - return best_match; - - return null; - } - - HttpListener MatchFromList(string host, string path, List list, out ListenerPrefix prefix) - { - prefix = null; - if (list == null) - return null; - - HttpListener best_match = null; - int best_length = -1; - - foreach (ListenerPrefix p in list) - { - string ppath = p.Path; - if (ppath.Length < best_length) - continue; - - if (path.StartsWith(ppath)) - { - best_length = ppath.Length; - best_match = p.Listener; - prefix = p; - } - } - - return best_match; - } - - void AddSpecial(List coll, ListenerPrefix prefix) - { - if (coll == null) - return; - - foreach (ListenerPrefix p in coll) - { - if (p.Path == prefix.Path) //TODO: code - throw new HttpListenerException(400, "Prefix already in use."); - } - coll.Add(prefix); - } - - bool RemoveSpecial(List coll, ListenerPrefix prefix) - { - if (coll == null) - return false; - - int c = coll.Count; - for (int i = 0; i < c; i++) - { - ListenerPrefix p = (ListenerPrefix)coll[i]; - if (p.Path == prefix.Path) - { - coll.RemoveAt(i); - return true; - } - } - return false; - } - - void CheckIfRemove() - { - if (prefixes.Count > 0) - return; - - List list = unhandled; - if (list != null && list.Count > 0) - return; - - list = all; - if (list != null && list.Count > 0) - return; - - EndPointManager.RemoveEndPoint(this, endpoint); - } - - public void Close() - { - _closed = true; - sock.Close(); - lock (unregistered) - { - // - // Clone the list because RemoveConnection can be called from Close - // - var connections = new List(unregistered.Keys); - - foreach (HttpConnection c in connections) - c.Close(true); - unregistered.Clear(); - } - } - - public void AddPrefix(ListenerPrefix prefix, HttpListener listener) - { - List current; - List future; - if (prefix.Host == "*") - { - do - { - current = unhandled; - future = (current != null) ? current.ToList() : new List(); - prefix.Listener = listener; - AddSpecial(future, prefix); - } while (Interlocked.CompareExchange(ref unhandled, future, current) != current); - return; - } - - if (prefix.Host == "+") - { - do - { - current = all; - future = (current != null) ? current.ToList() : new List(); - prefix.Listener = listener; - AddSpecial(future, prefix); - } while (Interlocked.CompareExchange(ref all, future, current) != current); - return; - } - - Dictionary prefs; - Dictionary p2; - do - { - prefs = prefixes; - if (prefs.ContainsKey(prefix)) - { - HttpListener other = (HttpListener)prefs[prefix]; - if (other != listener) // TODO: code. - throw new HttpListenerException(400, "There's another listener for " + prefix); - return; - } - p2 = new Dictionary(prefs); - p2[prefix] = listener; - } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs); - } - - public void RemovePrefix(ListenerPrefix prefix, HttpListener listener) - { - List current; - List future; - if (prefix.Host == "*") - { - do - { - current = unhandled; - future = (current != null) ? current.ToList() : new List(); - if (!RemoveSpecial(future, prefix)) - break; // Prefix not found - } while (Interlocked.CompareExchange(ref unhandled, future, current) != current); - CheckIfRemove(); - return; - } - - if (prefix.Host == "+") - { - do - { - current = all; - future = (current != null) ? current.ToList() : new List(); - if (!RemoveSpecial(future, prefix)) - break; // Prefix not found - } while (Interlocked.CompareExchange(ref all, future, current) != current); - CheckIfRemove(); - return; - } - - Dictionary prefs; - Dictionary p2; - do - { - prefs = prefixes; - if (!prefs.ContainsKey(prefix)) - break; - - p2 = new Dictionary(prefs); - p2.Remove(prefix); - } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs); - CheckIfRemove(); - } - } -} diff --git a/SocketHttpListener/Net/EndPointManager.cs b/SocketHttpListener/Net/EndPointManager.cs deleted file mode 100644 index 557caa59a3..0000000000 --- a/SocketHttpListener/Net/EndPointManager.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Net; -using System.Reflection; -using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using SocketHttpListener.Primitives; - -namespace SocketHttpListener.Net -{ - sealed class EndPointManager - { - // Dictionary> - static Dictionary> ip_to_endpoints = new Dictionary>(); - - private EndPointManager() - { - } - - public static void AddListener(ILogger logger, HttpListener listener) - { - List added = new List(); - try - { - lock (ip_to_endpoints) - { - foreach (string prefix in listener.Prefixes) - { - AddPrefixInternal(logger, prefix, listener); - added.Add(prefix); - } - } - } - catch - { - foreach (string prefix in added) - { - RemovePrefix(logger, prefix, listener); - } - throw; - } - } - - public static void AddPrefix(ILogger logger, string prefix, HttpListener listener) - { - lock (ip_to_endpoints) - { - AddPrefixInternal(logger, prefix, listener); - } - } - - static void AddPrefixInternal(ILogger logger, string p, HttpListener listener) - { - ListenerPrefix lp = new ListenerPrefix(p); - if (lp.Path.IndexOf('%') != -1) - throw new HttpListenerException(400, "Invalid path."); - - if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) // TODO: Code? - throw new HttpListenerException(400, "Invalid path."); - - // listens on all the interfaces if host name cannot be parsed by IPAddress. - EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; - epl.AddPrefix(lp, listener); - } - - private static IPAddress GetIpAnyAddress(HttpListener listener) - { - return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any; - } - - static async Task GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure) - { - var networkManager = listener.NetworkManager; - - IPAddress addr; - if (host == "*" || host == "+") - addr = GetIpAnyAddress(listener); - else if (IPAddress.TryParse(host, out addr) == false) - { - try - { - var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)); - - addr = (all.Length == 0 ? null : IPAddress.Parse(all[0].Address)) ?? - GetIpAnyAddress(listener); - } - catch - { - addr = GetIpAnyAddress(listener); - } - } - - Dictionary p = null; // Dictionary - if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p)) - { - p = new Dictionary(); - ip_to_endpoints[addr.ToString()] = p; - } - - EndPointListener epl = null; - if (p.ContainsKey(port)) - { - epl = (EndPointListener)p[port]; - } - else - { - epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); - p[port] = epl; - } - - return epl; - } - - public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep) - { - lock (ip_to_endpoints) - { - // Dictionary p - Dictionary p; - if (ip_to_endpoints.TryGetValue(ep.Address.ToString(), out p)) - { - p.Remove(ep.Port); - if (p.Count == 0) - { - ip_to_endpoints.Remove(ep.Address.ToString()); - } - } - epl.Close(); - } - } - - public static void RemoveListener(ILogger logger, HttpListener listener) - { - lock (ip_to_endpoints) - { - foreach (string prefix in listener.Prefixes) - { - RemovePrefixInternal(logger, prefix, listener); - } - } - } - - public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener) - { - lock (ip_to_endpoints) - { - RemovePrefixInternal(logger, prefix, listener); - } - } - - static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener) - { - ListenerPrefix lp = new ListenerPrefix(prefix); - if (lp.Path.IndexOf('%') != -1) - return; - - if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) - return; - - EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; - epl.RemovePrefix(lp, listener); - } - } -} diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index 494094bbfa..4b4c9bad4f 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -23,7 +23,7 @@ sealed class HttpConnection const int BufferSize = 8192; Socket _socket; Stream _stream; - EndPointListener _epl; + HttpEndPointListener _epl; MemoryStream _memoryStream; byte[] _buffer; HttpListenerContext _context; @@ -48,7 +48,7 @@ sealed class HttpConnection private readonly IFileSystem _fileSystem; private readonly IEnvironmentInfo _environment; - public HttpConnection(ILogger logger, Socket socket, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + public HttpConnection(ILogger logger, Socket socket, HttpEndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; this._socket = socket; @@ -86,7 +86,10 @@ public HttpConnection(ILogger logger, Socket socket, EndPointListener epl, bool }); _stream = ssl_stream; + } + if (ssl_stream != null) + { ssl_stream.AuthenticateAsServer(cert, false, (SslProtocols)ServicePointManager.SecurityProtocol, false); } Init(); diff --git a/SocketHttpListener/Net/HttpEndPointListener.cs b/SocketHttpListener/Net/HttpEndPointListener.cs new file mode 100644 index 0000000000..f40cafab82 --- /dev/null +++ b/SocketHttpListener/Net/HttpEndPointListener.cs @@ -0,0 +1,527 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; +using ProtocolType = MediaBrowser.Model.Net.ProtocolType; +using SocketType = MediaBrowser.Model.Net.SocketType; + +namespace SocketHttpListener.Net +{ + internal sealed class HttpEndPointListener + { + private HttpListener _listener; + private IPEndPoint _endpoint; + private Socket _socket; + private Dictionary _prefixes; + private List _unhandledPrefixes; // host = '*' + private List _allPrefixes; // host = '+' + private X509Certificate _cert; + private bool _secure; + private Dictionary _unregisteredConnections; + + private readonly ILogger _logger; + private bool _closed; + private bool _enableDualMode; + private readonly ICryptoProvider _cryptoProvider; + private readonly ISocketFactory _socketFactory; + private readonly ITextEncoding _textEncoding; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environment; + + public HttpEndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert, ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + { + this._listener = listener; + _logger = logger; + _cryptoProvider = cryptoProvider; + _socketFactory = socketFactory; + _memoryStreamFactory = memoryStreamFactory; + _textEncoding = textEncoding; + _fileSystem = fileSystem; + _environment = environment; + + this._secure = secure; + this._cert = cert; + + _enableDualMode = addr.Equals(IPAddress.IPv6Any); + _endpoint = new IPEndPoint(addr, port); + + _prefixes = new Dictionary(); + _unregisteredConnections = new Dictionary(); + + CreateSocket(); + } + + internal HttpListener Listener + { + get + { + return _listener; + } + } + + private void CreateSocket() + { + try + { + _socket = CreateSocket(_endpoint.Address.AddressFamily, _enableDualMode); + } + catch (SocketCreateException ex) + { + if (_enableDualMode && _endpoint.Address.Equals(IPAddress.IPv6Any) && + (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || + // mono on bsd is throwing this + string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase))) + { + _endpoint = new IPEndPoint(IPAddress.Any, _endpoint.Port); + _enableDualMode = false; + _socket = CreateSocket(_endpoint.Address.AddressFamily, _enableDualMode); + } + else + { + throw; + } + } + + try + { + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + catch (SocketException) + { + // This is not supported on all operating systems (qnap) + } + + _socket.Bind(_endpoint); + + // This is the number TcpListener uses. + _socket.Listen(2147483647); + + Accept(_socket, this); + + _closed = false; + } + + private static void Accept(Socket socket, HttpEndPointListener epl) + { + var acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.UserToken = epl; + acceptEventArg.Completed += new EventHandler(OnAccept); + + Socket dummy = null; + Accept(socket, acceptEventArg, ref dummy); + } + + private static void Accept(Socket socket, SocketAsyncEventArgs acceptEventArg, ref Socket accepted) + { + // acceptSocket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; + + try + { + bool willRaiseEvent = socket.AcceptAsync(acceptEventArg); + + if (!willRaiseEvent) + { + ProcessAccept(acceptEventArg); + } + } + catch + { + if (accepted != null) + { + try + { +#if NET46 + accepted.Close(); +#else + accepted.Dispose(); +#endif + } + catch + { + } + accepted = null; + } + } + } + + // This method is the callback method associated with Socket.AcceptAsync + // operations and is invoked when an accept operation is complete + // + private static void OnAccept(object sender, SocketAsyncEventArgs e) + { + ProcessAccept(e); + } + + private static void ProcessAccept(SocketAsyncEventArgs args) + { + HttpEndPointListener epl = (HttpEndPointListener)args.UserToken; + + if (epl._closed) + { + return; + } + + // http://msdn.microsoft.com/en-us/library/system.net.sockets.acceptSocket.acceptasync%28v=vs.110%29.aspx + // Under certain conditions ConnectionReset can occur + // Need to attept to re-accept + if (args.SocketError == SocketError.ConnectionReset) + { + epl._logger.Error("SocketError.ConnectionReset reported. Attempting to re-accept."); + Accept(epl._socket, epl); + return; + } + + var acceptSocket = args.AcceptSocket; + if (acceptSocket != null) + { + epl.ProcessAccept(acceptSocket); + } + + // Accept the next connection request + Accept(epl._socket, args, ref acceptSocket); + } + + private Socket CreateSocket(AddressFamily addressFamily, bool dualMode) + { + try + { + var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); + + if (dualMode) + { + socket.DualMode = true; + } + + return socket; + } + catch (SocketException ex) + { + throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex); + } + catch (ArgumentException ex) + { + if (dualMode) + { + // Mono for BSD incorrectly throws ArgumentException instead of SocketException + throw new SocketCreateException("AddressFamilyNotSupported", ex); + } + else + { + throw; + } + } + } + + private void TryClose(Socket accepted) + { + try + { + accepted.Close(); + } + catch + { + + } + } + + private void ProcessAccept(Socket accepted) + { + try + { + var listener = this; + + if (listener._secure && listener._cert == null) + { + accepted.Close(); + return; + } + + HttpConnection conn = new HttpConnection(_logger, accepted, listener, _secure, _cert, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem, _environment); + + //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId); + lock (listener._unregisteredConnections) + { + listener._unregisteredConnections[conn] = conn; + } + conn.BeginReadRequest(); + } + catch (Exception ex) + { + TryClose(accepted); + _logger.ErrorException("Error in ProcessAccept", ex); + } + } + + internal void RemoveConnection(HttpConnection conn) + { + lock (_unregisteredConnections) + { + _unregisteredConnections.Remove(conn); + } + } + + public bool BindContext(HttpListenerContext context) + { + HttpListenerRequest req = context.Request; + ListenerPrefix prefix; + HttpListener listener = SearchListener(req.Url, out prefix); + if (listener == null) + return false; + + context.Connection.Prefix = prefix; + return true; + } + + public void UnbindContext(HttpListenerContext context) + { + if (context == null || context.Request == null) + return; + + _listener.UnregisterContext(context); + } + + private HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) + { + prefix = null; + if (uri == null) + return null; + + string host = uri.Host; + int port = uri.Port; + string path = WebUtility.UrlDecode(uri.AbsolutePath); + string pathSlash = path[path.Length - 1] == '/' ? path : path + "/"; + + HttpListener bestMatch = null; + int bestLength = -1; + + if (host != null && host != "") + { + Dictionary localPrefixes = _prefixes; + foreach (ListenerPrefix p in localPrefixes.Keys) + { + string ppath = p.Path; + if (ppath.Length < bestLength) + continue; + + if (p.Host != host || p.Port != port) + continue; + + if (path.StartsWith(ppath) || pathSlash.StartsWith(ppath)) + { + bestLength = ppath.Length; + bestMatch = localPrefixes[p]; + prefix = p; + } + } + if (bestLength != -1) + return bestMatch; + } + + List list = _unhandledPrefixes; + bestMatch = MatchFromList(host, path, list, out prefix); + + if (path != pathSlash && bestMatch == null) + bestMatch = MatchFromList(host, pathSlash, list, out prefix); + + if (bestMatch != null) + return bestMatch; + + list = _allPrefixes; + bestMatch = MatchFromList(host, path, list, out prefix); + + if (path != pathSlash && bestMatch == null) + bestMatch = MatchFromList(host, pathSlash, list, out prefix); + + if (bestMatch != null) + return bestMatch; + + return null; + } + + private HttpListener MatchFromList(string host, string path, List list, out ListenerPrefix prefix) + { + prefix = null; + if (list == null) + return null; + + HttpListener bestMatch = null; + int bestLength = -1; + + foreach (ListenerPrefix p in list) + { + string ppath = p.Path; + if (ppath.Length < bestLength) + continue; + + if (path.StartsWith(ppath)) + { + bestLength = ppath.Length; + bestMatch = p._listener; + prefix = p; + } + } + + return bestMatch; + } + + private void AddSpecial(List list, ListenerPrefix prefix) + { + if (list == null) + return; + + foreach (ListenerPrefix p in list) + { + if (p.Path == prefix.Path) + throw new Exception("net_listener_already"); + } + list.Add(prefix); + } + + private bool RemoveSpecial(List list, ListenerPrefix prefix) + { + if (list == null) + return false; + + int c = list.Count; + for (int i = 0; i < c; i++) + { + ListenerPrefix p = list[i]; + if (p.Path == prefix.Path) + { + list.RemoveAt(i); + return true; + } + } + return false; + } + + private void CheckIfRemove() + { + if (_prefixes.Count > 0) + return; + + List list = _unhandledPrefixes; + if (list != null && list.Count > 0) + return; + + list = _allPrefixes; + if (list != null && list.Count > 0) + return; + + HttpEndPointManager.RemoveEndPoint(this, _endpoint); + } + + public void Close() + { + _closed = true; + _socket.Close(); + lock (_unregisteredConnections) + { + // Clone the list because RemoveConnection can be called from Close + var connections = new List(_unregisteredConnections.Keys); + + foreach (HttpConnection c in connections) + c.Close(true); + _unregisteredConnections.Clear(); + } + } + + public void AddPrefix(ListenerPrefix prefix, HttpListener listener) + { + List current; + List future; + if (prefix.Host == "*") + { + do + { + current = _unhandledPrefixes; + future = current != null ? new List(current) : new List(); + prefix._listener = listener; + AddSpecial(future, prefix); + } while (Interlocked.CompareExchange(ref _unhandledPrefixes, future, current) != current); + return; + } + + if (prefix.Host == "+") + { + do + { + current = _allPrefixes; + future = current != null ? new List(current) : new List(); + prefix._listener = listener; + AddSpecial(future, prefix); + } while (Interlocked.CompareExchange(ref _allPrefixes, future, current) != current); + return; + } + + Dictionary prefs, p2; + do + { + prefs = _prefixes; + if (prefs.ContainsKey(prefix)) + { + throw new Exception("net_listener_already"); + } + p2 = new Dictionary(prefs); + p2[prefix] = listener; + } while (Interlocked.CompareExchange(ref _prefixes, p2, prefs) != prefs); + } + + public void RemovePrefix(ListenerPrefix prefix, HttpListener listener) + { + List current; + List future; + if (prefix.Host == "*") + { + do + { + current = _unhandledPrefixes; + future = current != null ? new List(current) : new List(); + if (!RemoveSpecial(future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange(ref _unhandledPrefixes, future, current) != current); + + CheckIfRemove(); + return; + } + + if (prefix.Host == "+") + { + do + { + current = _allPrefixes; + future = current != null ? new List(current) : new List(); + if (!RemoveSpecial(future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange(ref _allPrefixes, future, current) != current); + CheckIfRemove(); + return; + } + + Dictionary prefs, p2; + do + { + prefs = _prefixes; + if (!prefs.ContainsKey(prefix)) + break; + + p2 = new Dictionary(prefs); + p2.Remove(prefix); + } while (Interlocked.CompareExchange(ref _prefixes, p2, prefs) != prefs); + CheckIfRemove(); + } + } +} diff --git a/SocketHttpListener/Net/HttpEndPointManager.cs b/SocketHttpListener/Net/HttpEndPointManager.cs new file mode 100644 index 0000000000..67910a8834 --- /dev/null +++ b/SocketHttpListener/Net/HttpEndPointManager.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + internal sealed class HttpEndPointManager + { + private static Dictionary> s_ipEndPoints = new Dictionary>(); + + private HttpEndPointManager() + { + } + + public static void AddListener(ILogger logger, HttpListener listener) + { + List added = new List(); + try + { + lock ((s_ipEndPoints as ICollection).SyncRoot) + { + foreach (string prefix in listener.Prefixes) + { + AddPrefixInternal(logger, prefix, listener); + added.Add(prefix); + } + } + } + catch + { + foreach (string prefix in added) + { + RemovePrefix(logger, prefix, listener); + } + throw; + } + } + + public static void AddPrefix(ILogger logger, string prefix, HttpListener listener) + { + lock ((s_ipEndPoints as ICollection).SyncRoot) + { + AddPrefixInternal(logger, prefix, listener); + } + } + + private static void AddPrefixInternal(ILogger logger, string p, HttpListener listener) + { + int start = p.IndexOf(':') + 3; + int colon = p.IndexOf(':', start); + if (colon != -1) + { + // root can't be -1 here, since we've already checked for ending '/' in ListenerPrefix. + int root = p.IndexOf('/', colon, p.Length - colon); + string portString = p.Substring(colon + 1, root - colon - 1); + + int port; + if (!int.TryParse(portString, out port) || port <= 0 || port >= 65536) + { + throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_port"); + } + } + + ListenerPrefix lp = new ListenerPrefix(p); + if (lp.Host != "*" && lp.Host != "+" && Uri.CheckHostName(lp.Host) == UriHostNameType.Unknown) + throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_listener_host"); + + if (lp.Path.IndexOf('%') != -1) + throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path"); + + if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) + throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path"); + + // listens on all the interfaces if host name cannot be parsed by IPAddress. + HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure); + epl.AddPrefix(lp, listener); + } + + private static HttpEndPointListener GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure) + { + IPAddress addr; + if (host == "*" || host == "+") + { + addr = IPAddress.Any; + } + else + { + const int NotSupportedErrorCode = 50; + try + { + addr = Dns.GetHostAddresses(host)[0]; + } + catch + { + // Throw same error code as windows, request is not supported. + throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported"); + } + + if (IPAddress.Any.Equals(addr)) + { + // Don't support listening to 0.0.0.0, match windows behavior. + throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported"); + } + } + + Dictionary p = null; + if (s_ipEndPoints.ContainsKey(addr)) + { + p = s_ipEndPoints[addr]; + } + else + { + p = new Dictionary(); + s_ipEndPoints[addr] = p; + } + + HttpEndPointListener epl = null; + if (p.ContainsKey(port)) + { + epl = p[port]; + } + else + { + try + { + epl = new HttpEndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); + } + catch (SocketException ex) + { + throw new HttpListenerException(ex.ErrorCode, ex.Message); + } + p[port] = epl; + } + + return epl; + } + + public static void RemoveEndPoint(HttpEndPointListener epl, IPEndPoint ep) + { + lock ((s_ipEndPoints as ICollection).SyncRoot) + { + Dictionary p = null; + p = s_ipEndPoints[ep.Address]; + p.Remove(ep.Port); + if (p.Count == 0) + { + s_ipEndPoints.Remove(ep.Address); + } + epl.Close(); + } + } + + public static void RemoveListener(ILogger logger, HttpListener listener) + { + lock ((s_ipEndPoints as ICollection).SyncRoot) + { + foreach (string prefix in listener.Prefixes) + { + RemovePrefixInternal(logger, prefix, listener); + } + } + } + + public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener) + { + lock ((s_ipEndPoints as ICollection).SyncRoot) + { + RemovePrefixInternal(logger, prefix, listener); + } + } + + private static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener) + { + ListenerPrefix lp = new ListenerPrefix(prefix); + if (lp.Path.IndexOf('%') != -1) + return; + + if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) + return; + + HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure); + epl.RemovePrefix(lp, listener); + } + } +} diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs index 32c5e90e09..fafcd1bef8 100644 --- a/SocketHttpListener/Net/HttpListener.cs +++ b/SocketHttpListener/Net/HttpListener.cs @@ -185,7 +185,7 @@ public void Close() void Close(bool force) { CheckDisposed(); - EndPointManager.RemoveListener(_logger, this); + HttpEndPointManager.RemoveListener(_logger, this); Cleanup(force); } @@ -230,7 +230,7 @@ public void Start() if (listening) return; - EndPointManager.AddListener(_logger, this); + HttpEndPointManager.AddListener(_logger, this); listening = true; } diff --git a/SocketHttpListener/Net/HttpListenerPrefixCollection.cs b/SocketHttpListener/Net/HttpListenerPrefixCollection.cs index 0b05539eea..53efcb0fad 100644 --- a/SocketHttpListener/Net/HttpListenerPrefixCollection.cs +++ b/SocketHttpListener/Net/HttpListenerPrefixCollection.cs @@ -36,13 +36,13 @@ public bool IsSynchronized public void Add(string uriPrefix) { listener.CheckDisposed(); - ListenerPrefix.CheckUri(uriPrefix); + //ListenerPrefix.CheckUri(uriPrefix); if (prefixes.Contains(uriPrefix)) return; prefixes.Add(uriPrefix); if (listener.IsListening) - EndPointManager.AddPrefix(_logger, uriPrefix, listener); + HttpEndPointManager.AddPrefix(_logger, uriPrefix, listener); } public void Clear() @@ -50,7 +50,7 @@ public void Clear() listener.CheckDisposed(); prefixes.Clear(); if (listener.IsListening) - EndPointManager.RemoveListener(_logger, listener); + HttpEndPointManager.RemoveListener(_logger, listener); } public bool Contains(string uriPrefix) @@ -89,7 +89,7 @@ public bool Remove(string uriPrefix) bool result = prefixes.Remove(uriPrefix); if (result && listener.IsListening) - EndPointManager.RemovePrefix(_logger, uriPrefix, listener); + HttpEndPointManager.RemovePrefix(_logger, uriPrefix, listener); return result; } diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs index c0a94e289f..dbaece22fd 100644 --- a/SocketHttpListener/Net/HttpListenerRequest.cs +++ b/SocketHttpListener/Net/HttpListenerRequest.cs @@ -407,19 +407,13 @@ internal bool FlushInput() byte[] bytes = new byte[length]; while (true) { - // TODO: test if MS has a timeout when doing this try { - var task = InputStream.ReadAsync(bytes, 0, length); - var result = Task.WaitAll(new[] { task }, 1000); - if (!result) - { + IAsyncResult ares = InputStream.BeginRead(bytes, 0, length, null, null); + if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne(1000)) return false; - } - if (task.Result <= 0) - { + if (InputStream.EndRead(ares) <= 0) return true; - } } catch (ObjectDisposedException) { diff --git a/SocketHttpListener/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs index 605b7b88cf..99bb118e52 100644 --- a/SocketHttpListener/Net/ListenerPrefix.cs +++ b/SocketHttpListener/Net/ListenerPrefix.cs @@ -4,50 +4,50 @@ namespace SocketHttpListener.Net { - sealed class ListenerPrefix + internal sealed class ListenerPrefix { - string original; - string host; - ushort port; - string path; - bool secure; - IPAddress[] addresses; - public HttpListener Listener; + private string _original; + private string _host; + private ushort _port; + private string _path; + private bool _secure; + private IPAddress[] _addresses; + internal HttpListener _listener; public ListenerPrefix(string prefix) { - this.original = prefix; + _original = prefix; Parse(prefix); } public override string ToString() { - return original; + return _original; } public IPAddress[] Addresses { - get { return addresses; } - set { addresses = value; } + get { return _addresses; } + set { _addresses = value; } } public bool Secure { - get { return secure; } + get { return _secure; } } public string Host { - get { return host; } + get { return _host; } } public int Port { - get { return (int)port; } + get { return _port; } } public string Path { - get { return path; } + get { return _path; } } // Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection. @@ -57,92 +57,46 @@ public override bool Equals(object o) if (other == null) return false; - return (original == other.original); + return (_original == other._original); } public override int GetHashCode() { - return original.GetHashCode(); + return _original.GetHashCode(); } - void Parse(string uri) + private void Parse(string uri) { ushort default_port = 80; if (uri.StartsWith("https://")) { default_port = 443; - secure = true; + _secure = true; } int length = uri.Length; int start_host = uri.IndexOf(':') + 3; if (start_host >= length) - throw new ArgumentException("No host specified."); + throw new ArgumentException("net_listener_host"); int colon = uri.IndexOf(':', start_host, length - start_host); int root; if (colon > 0) { - host = uri.Substring(start_host, colon - start_host); + _host = uri.Substring(start_host, colon - start_host); root = uri.IndexOf('/', colon, length - colon); - port = (ushort)Int32.Parse(uri.Substring(colon + 1, root - colon - 1)); - path = uri.Substring(root); + _port = (ushort)int.Parse(uri.Substring(colon + 1, root - colon - 1)); + _path = uri.Substring(root); } else { root = uri.IndexOf('/', start_host, length - start_host); - host = uri.Substring(start_host, root - start_host); - port = default_port; - path = uri.Substring(root); + _host = uri.Substring(start_host, root - start_host); + _port = default_port; + _path = uri.Substring(root); } - if (path.Length != 1) - path = path.Substring(0, path.Length - 1); - } - - public static void CheckUri(string uri) - { - if (uri == null) - throw new ArgumentNullException("uriPrefix"); - - if (!uri.StartsWith("http://") && !uri.StartsWith("https://")) - throw new ArgumentException("Only 'http' and 'https' schemes are supported."); - - int length = uri.Length; - int start_host = uri.IndexOf(':') + 3; - if (start_host >= length) - throw new ArgumentException("No host specified."); - - int colon = uri.IndexOf(':', start_host, length - start_host); - if (start_host == colon) - throw new ArgumentException("No host specified."); - - int root; - if (colon > 0) - { - root = uri.IndexOf('/', colon, length - colon); - if (root == -1) - throw new ArgumentException("No path specified."); - - try - { - int p = Int32.Parse(uri.Substring(colon + 1, root - colon - 1)); - if (p <= 0 || p >= 65536) - throw new Exception(); - } - catch - { - throw new ArgumentException("Invalid port."); - } - } - else - { - root = uri.IndexOf('/', start_host, length - start_host); - if (root == -1) - throw new ArgumentException("No path specified."); - } - - if (uri[uri.Length - 1] != '/') - throw new ArgumentException("The prefix must end with '/'"); + if (_path.Length != 1) + _path = _path.Substring(0, _path.Length - 1); } } } diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj index 8e9e01dc89..224e5a9a34 100644 --- a/SocketHttpListener/SocketHttpListener.csproj +++ b/SocketHttpListener/SocketHttpListener.csproj @@ -62,10 +62,10 @@ - - + + diff --git a/ThirdParty/emby/Emby.Server.CinemaMode.dll b/ThirdParty/emby/Emby.Server.CinemaMode.dll index 6d69b34bd1..cf3a0f1402 100644 Binary files a/ThirdParty/emby/Emby.Server.CinemaMode.dll and b/ThirdParty/emby/Emby.Server.CinemaMode.dll differ diff --git a/ThirdParty/emby/Emby.Server.Connect.dll b/ThirdParty/emby/Emby.Server.Connect.dll index d8992201ab..ec30855af0 100644 Binary files a/ThirdParty/emby/Emby.Server.Connect.dll and b/ThirdParty/emby/Emby.Server.Connect.dll differ diff --git a/ThirdParty/emby/Emby.Server.MediaEncoding.dll b/ThirdParty/emby/Emby.Server.MediaEncoding.dll index ff930f64df..361f8f679b 100644 Binary files a/ThirdParty/emby/Emby.Server.MediaEncoding.dll and b/ThirdParty/emby/Emby.Server.MediaEncoding.dll differ diff --git a/ThirdParty/emby/Emby.Server.Sync.dll b/ThirdParty/emby/Emby.Server.Sync.dll index 93a2d74d5b..a9b845424c 100644 Binary files a/ThirdParty/emby/Emby.Server.Sync.dll and b/ThirdParty/emby/Emby.Server.Sync.dll differ