mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-27 20:01:57 +01:00
1 line
225 KiB
Plaintext
1 line
225 KiB
Plaintext
{"version":3,"sources":["webpack://[name]/webpack/universalModuleDefinition","webpack://[name]/webpack/bootstrap","webpack://[name]/./node_modules/node-fetch/browser.js","webpack://[name]/./src/events.js","webpack://[name]/./src/appStorage.js","webpack://[name]/./src/apiClient.js","webpack://[name]/./src/apiClientCore.js","webpack://[name]/./src/connectionManager.js","webpack://[name]/./src/credentials.js","webpack://[name]/./src/index.js"],"names":["root","factory","exports","module","define","amd","this","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","global","self","window","Error","getGlobal","fetch","default","Headers","Request","Response","getCallbacks","obj","_callbacks","list","on","eventName","fn","push","off","indexOf","splice","trigger","eventObject","type","eventArgs","additionalArgs","arguments","length","callbacks","slice","forEach","apply","onCachePutFail","e","console","log","updateCache","instance","cache","put","JSON","stringify","localData","catch","onCacheOpened","result","AppStore","caches","open","then","err","localStorage","setItem","getItem","removeItem","getInstance","reportRateLimits","timeupdate","volumechange","redetectBitrate","stopBitrateDetection","accessToken","enableAutomaticBitrateDetection","setTimeout","redetectBitrateInternal","detectBitrate","detectTimeout","clearTimeout","replaceAll","originalString","strReplace","strWith","reg","RegExp","replace","onFetchFail","url","response","events","status","errorCode","headers","paramsToString","params","values","encodeURIComponent","join","fetchWithTimeout","options","timeoutMs","Promise","resolve","reject","timeout","credentials","error","getFetchPromise","request","dataType","accept","fetchRequest","method","contentType","data","body","cancelReportPlaybackProgressPromise","reportPlaybackProgressCancel","setSavedEndpointInfo","info","_endPointInfo","getCachedUser","userId","serverId","json","appStorage","parse","onWebSocketMessage","msg","onMessageReceivedInternal","messageIdsReceived","messageId","MessageId","MessageType","_currentUser","Data","Id","getCurrentUserId","debug","sendWebSocketMessage","clearKeepAlive","keepAliveInterval","setInterval","scheduleKeepAlive","clearInterval","onWebSocketOpen","onWebSocketError","normalizeReturnBitrate","bitrate","lastDetectedBitrate","Math","round","getMaxBandwidth","maxRate","min","lastDetectedBitrateTime","Date","getTime","detectBitrateWithEndpointInfo","endpointInfo","IsInNetwork","detectBitrateInternal","tests","index","currentBitrate","test","getDownloadSpeed","bytes","threshold","getRemoteImagePrefix","urlPrefix","artist","encodeName","person","genre","musicGenre","studio","itemId","normalizeImageOptions","ratio","devicePixelRatio","minScale","max","width","height","maxWidth","maxHeight","quality","getDefaultImageQuality","ApiClient","serverAddress","appName","appVersion","deviceName","deviceId","_serverInfo","_serverAddress","_deviceId","_deviceName","_appName","_appVersion","currentServerInfo","serverInfo","AccessToken","auth","val","toLowerCase","changed","onNetworkChange","charAt","enableReconnection","lastFetch","text","toString","previousServerAddress","tryReconnect","retryCount","addresses","addressesStrings","LocalAddress","ManualAddress","RemoteAddress","state","numAddresses","rejects","map","resolved","getUrl","getTryConnectPromise","tryReconnectInternal","fetchWithFailover","innerError","includeAuthorization","setRequestHeaders","enableAutomaticNetworking","accessKey","UserId","Name","enableCache","user","serverPromise","getUser","userObject","ServerId","closeWebSocket","done","setAuthenticationInfo","ajax","password","postData","Username","Pw","afterOnAuthenticated","onAuthenticated","isWebSocketOpenOrConnecting","isWebSocketSupported","openWebSocket","apiClient","socket","webSocket","WebSocket","onmessage","onopen","onerror","onclose","_webSocket","readyState","OPEN","close","send","isWebSocketOpen","CONNECTING","server","serverUrl","split","substring","byteSize","Size","now","responseTimeSeconds","bytesPerSecond","force","getEndpointInfo","getJSON","idList","isRead","suffix","Ids","id","channelIds","item","feature","setSystemInfo","TargetId","app","client","deviceProfile","DeviceProfile","liveStreamId","LiveStreamId","path","installationId","guid","version","AssemblyGuid","DeviceId","PackageType","refreshLibrary","libraryOptions","collectionType","LibraryOptions","newName","virtualFolderName","mediaPath","networkSharePath","pathInfo","Path","NetworkPath","PathInfo","imageType","imageIndex","playSessionId","PlaySessionId","newIndex","api_key","file","startsWith","reader","FileReader","onabort","onload","target","lastIndexOf","readAsDataURL","ImageTags","Thumb","tag","getImageUrl","ParentThumbItemId","ParentThumbImageTag","currentPassword","newPassword","CurrentPw","NewPw","configuration","policy","triggers","isMinServerVersion","getItems","assign","SortBy","SortOrder","Filters","Recursive","CollapseBoxSetItems","ExcludeLocationTypes","inherit","InheritFromParent","SearchHints","date","formatDigit","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","DatePlayed","getDateParamValue","isFavorite","likes","lastPlaybackProgressReport","lastPlaybackProgressReportTicks","EventName","reportRateLimitTime","msSinceLastReport","newPositionTicks","PositionTicks","expectedReportTicks","abs","undefined","reportPlaybackProgressTimeout","lastPlaybackProgressOptions","reportPlaybackProgressPromise","promise","cancelled","resetPromise","delay","lastOptions","sendReport","finally","actions","syncJobItemId","itemIds","targetId","ItemIds","sessionId","command","ajaxOptions","review","packageId","minRating","maxRating","limit","MinRating","MaxRating","Limit","savedValue","endPointInfo","_serverVersion","Version","serverVersion","a","b","aVal","parseInt","bVal","compareVersions","isLocalId","str","isLocalViewId","isTopLevelLocalViewId","stripLocalPrefix","res","stripStart","find","substr","convertGuidToLocal","adjustGuidProperties","downloadedItem","SeriesId","SeasonId","AlbumId","ParentId","ParentPrimaryImageItemId","PrimaryImageItemId","ParentLogoItemId","ParentBackdropItemId","ParentBackdropImageTags","getLocalView","getLocalFolders","views","localView","downloadsTitleText","Type","IsFolder","ApiClientCore","clientName","applicationVersion","localAssetManager","onFailure","getPlaybackInfo","getLocalItem","MediaSources","Item","SupportsDirectPlay","SupportsDirectStream","SupportsTranscoding","IsLocal","mediaSources","fileExists","LocalPath","exists","items","Items","TotalRecordCount","AlbumIds","getViewItems","ExcludeItemIds","exItems","ids","hasLocal","getItemsFromIds","basePromise","getUserViews","enableLocalView","filter","getViews","getNextUpEpisodes","IncludeItemTypes","getSeasons","seasonId","getEpisodes","getThemeMedia","getSpecialFeatures","getSimilarItems","updateFavoriteStatus","itemid","getScaledImageUrl","ItemId","reportPlaybackStart","libraryItem","MediaType","UserData","PlaybackPositionTicks","PlayedPercentage","RunTimeTicks","addOrUpdateLocalItem","reportPlaybackProgress","action","recordUserAction","reportPlaybackStopped","getIntros","getInstantMixFromItem","getItemDownloadUrl","ConnectionMode","getServerAddress","resolveFailure","State","updateServerInfo","systemInfo","ServerName","getEmbyServerUrl","baseUrl","handler","normalizeAddress","address","trim","stringEqualsIgnoreCase","str1","str2","ConnectionManager","credentialProvider","capabilities","saveCredentials","servers","Servers","updateDateLastAccessed","DateLastAccessed","User","addOrUpdateServer","afterConnected","onLocalUserSignIn","reportCapabilities","enableWebSocket","ensureWebSocket","_getOrAddApiClient","onLocalUserSignedIn","validateAuthentication","logoutOfServer","logoutInfo","logout","convertEndpointAddressToManualAddress","Address","EndpointAddress","parts","portString","isNaN","manualAddressOnly","connectionMode","tryConnectToAddress","LastConnectionMode","connectToServer","_apiClients","_minServerVersion","getServerInfo","getLastUsedServer","sort","addApiClient","existingServers","existingServer","clearData","getApiClient","getOrCreateApiClient","localUser","getCurrentUser","u","image","PrimaryImageTag","getUserImageUrl","supportsParams","imageUrl","supportsImageParams","promises","all","UserLinkType","j","numServers","ExchangeToken","getSavedServers","getAvailableServers","onFinish","foundServers","foundServer","NativeShell","findServers","responses","list1","list2","mergeServers","connectToServers","firstServer","minServerVersion","onSuccessfulConnection","verifyLocalAuthentication","enableAutoLogin","resolveActions","connectToAddress","urls","onFail","deleteServer","ConnectServerId","handleMessageReceived","Credentials","_credentials","clear","set","ensure","existing","require","AppStorage","Events"],"mappings":"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","file":"jellyfin-apiclient.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"jellyfin-apiclient\"] = factory();\n\telse\n\t\troot[\"jellyfin-apiclient\"] = factory();\n})(this, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","\"use strict\";\n\n// ref: https://github.com/tc39/proposal-global\nvar getGlobal = function () {\n\t// the only reliable means to get the global object is\n\t// `Function('return this')()`\n\t// However, this causes CSP violations in Chrome apps.\n\tif (typeof self !== 'undefined') { return self; }\n\tif (typeof window !== 'undefined') { return window; }\n\tif (typeof global !== 'undefined') { return global; }\n\tthrow new Error('unable to locate global object');\n}\n\nvar global = getGlobal();\n\nmodule.exports = exports = global.fetch;\n\n// Needed for TypeScript and Webpack.\nexports.default = global.fetch.bind(global);\n\nexports.Headers = global.Headers;\nexports.Request = global.Request;\nexports.Response = global.Response;","function getCallbacks(obj, name) {\n if (!obj) {\n throw new Error('obj cannot be null!');\n }\n\n obj._callbacks = obj._callbacks || {};\n\n let list = obj._callbacks[name];\n\n if (!list) {\n obj._callbacks[name] = [];\n list = obj._callbacks[name];\n }\n\n return list;\n}\n\nexport default {\n on(obj, eventName, fn) {\n const list = getCallbacks(obj, eventName);\n\n list.push(fn);\n },\n\n off(obj, eventName, fn) {\n const list = getCallbacks(obj, eventName);\n\n const i = list.indexOf(fn);\n if (i !== -1) {\n list.splice(i, 1);\n }\n },\n\n trigger(obj, eventName) {\n const eventObject = {\n type: eventName\n };\n\n const eventArgs = [];\n eventArgs.push(eventObject);\n\n const additionalArgs = arguments[2] || [];\n for (let i = 0, length = additionalArgs.length; i < length; i++) {\n eventArgs.push(additionalArgs[i]);\n }\n\n const callbacks = getCallbacks(obj, eventName).slice(0);\n\n callbacks.forEach((c) => {\n c.apply(obj, eventArgs);\n });\n }\n};\n","function onCachePutFail(e) {\n console.log(e);\n}\n\nfunction updateCache(instance) {\n const cache = instance.cache;\n if (cache) {\n cache.put('data', new Response(JSON.stringify(instance.localData))).catch(onCachePutFail);\n }\n}\n\nfunction onCacheOpened(result) {\n this.cache = result;\n this.localData = {};\n}\n\nclass AppStore {\n constructor() {\n try {\n if (self.caches) {\n caches.open('embydata').then(onCacheOpened.bind(this));\n }\n } catch (err) {\n console.log(`Error opening cache: ${err}`);\n }\n }\n\n setItem(name, value) {\n localStorage.setItem(name, value);\n const localData = this.localData;\n if (localData) {\n const changed = localData[name] !== value;\n if (changed) {\n localData[name] = value;\n updateCache(this);\n }\n }\n }\n\n static getInstance() {\n if (!AppStore.instance) {\n AppStore.instance = new AppStore();\n }\n\n return AppStore.instance;\n }\n\n getItem(name) {\n return localStorage.getItem(name);\n }\n\n removeItem(name) {\n localStorage.removeItem(name);\n const localData = this.localData;\n if (localData) {\n localData[name] = null;\n delete localData[name];\n updateCache(this);\n }\n }\n}\n\nexport default AppStore.getInstance();\n","import events from './events';\nimport appStorage from './appStorage';\n\n/** Report rate limits in ms for different events */\nconst reportRateLimits = {\n timeupdate: 10000,\n volumechange: 3000\n};\n\nfunction redetectBitrate(instance) {\n stopBitrateDetection(instance);\n\n if (instance.accessToken() && instance.enableAutomaticBitrateDetection !== false) {\n setTimeout(redetectBitrateInternal.bind(instance), 6000);\n }\n}\n\nfunction redetectBitrateInternal() {\n if (this.accessToken()) {\n this.detectBitrate();\n }\n}\n\nfunction stopBitrateDetection(instance) {\n if (instance.detectTimeout) {\n clearTimeout(instance.detectTimeout);\n }\n}\n\nfunction replaceAll(originalString, strReplace, strWith) {\n const reg = new RegExp(strReplace, 'ig');\n return originalString.replace(reg, strWith);\n}\n\nfunction onFetchFail(instance, url, response) {\n events.trigger(instance, 'requestfail', [\n {\n url,\n status: response.status,\n errorCode: response.headers ? response.headers.get('X-Application-Error-Code') : null\n }\n ]);\n}\n\nfunction paramsToString(params) {\n const values = [];\n\n for (const key in params) {\n const value = params[key];\n\n if (value !== null && value !== undefined && value !== '') {\n values.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n }\n }\n return values.join('&');\n}\n\nfunction fetchWithTimeout(url, options, timeoutMs) {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(reject, timeoutMs);\n\n options = options || {};\n options.credentials = 'same-origin';\n\n fetch(url, options)\n .then((response) => {\n clearTimeout(timeout);\n resolve(response);\n })\n .catch((error) => {\n clearTimeout(timeout);\n reject(error);\n });\n });\n}\n\nfunction getFetchPromise(request) {\n const headers = request.headers || {};\n\n if (request.dataType === 'json') {\n headers.accept = 'application/json';\n }\n\n const fetchRequest = {\n headers,\n method: request.type,\n credentials: 'same-origin'\n };\n\n let contentType = request.contentType;\n\n if (request.data) {\n if (typeof request.data === 'string') {\n fetchRequest.body = request.data;\n } else {\n fetchRequest.body = paramsToString(request.data);\n\n contentType = contentType || 'application/x-www-form-urlencoded; charset=UTF-8';\n }\n }\n\n if (contentType) {\n headers['Content-Type'] = contentType;\n }\n\n\n fetchRequest.dataType=\"json\"\n fetchRequest.contentType=\"application/json\"\n fetchRequest.url=request.url;\n delete fetchRequest.credentials\n console.log('na hoffe');\n console.log(fetchRequest);\n\n\n if (!request.timeout) {\n return fetch(request.url, fetchRequest);\n }\n\n return fetchWithTimeout(request.url, fetchRequest, request.timeout);\n}\n\nfunction cancelReportPlaybackProgressPromise(instance) {\n if (typeof instance.reportPlaybackProgressCancel === 'function') instance.reportPlaybackProgressCancel();\n}\n\n/**\n * Creates a new api client instance\n * @param {String} serverAddress\n * @param {String} appName\n * @param {String} appVersion\n */\nclass ApiClient {\n constructor(serverAddress, appName, appVersion, deviceName, deviceId) {\n if (!serverAddress) {\n throw new Error('Must supply a serverAddress');\n }\n\n console.debug(`ApiClient serverAddress: ${serverAddress}`);\n console.debug(`ApiClient appName: ${appName}`);\n console.debug(`ApiClient appVersion: ${appVersion}`);\n console.debug(`ApiClient deviceName: ${deviceName}`);\n console.debug(`ApiClient deviceId: ${deviceId}`);\n\n this._serverInfo = {};\n this._serverAddress = serverAddress;\n this._deviceId = deviceId;\n this._deviceName = deviceName;\n this._appName = appName;\n this._appVersion = appVersion;\n }\n\n appName() {\n return this._appName;\n }\n\n setRequestHeaders(headers) {\n const currentServerInfo = this.serverInfo();\n const appName = this._appName;\n const accessToken = currentServerInfo.AccessToken;\n\n const values = [];\n\n if (appName) {\n values.push(`Client=\"${appName}\"`);\n }\n\n if (this._deviceName) {\n values.push(`Device=\"${this._deviceName}\"`);\n }\n\n if (this._deviceId) {\n values.push(`DeviceId=\"${this._deviceId}\"`);\n }\n\n if (this._appVersion) {\n values.push(`Version=\"${this._appVersion}\"`);\n }\n\n if (accessToken) {\n values.push(`Token=\"${accessToken}\"`);\n }\n\n if (values.length) {\n const auth = `MediaBrowser ${values.join(', ')}`;\n //headers.Authorization = auth;\n headers['X-Emby-Authorization'] = auth;\n }\n }\n\n appVersion() {\n return this._appVersion;\n }\n\n deviceName() {\n return this._deviceName;\n }\n\n deviceId() {\n return this._deviceId;\n }\n\n /**\n * Gets the server address.\n */\n serverAddress(val) {\n if (val != null) {\n if (val.toLowerCase().indexOf('http') !== 0) {\n throw new Error(`Invalid url: ${val}`);\n }\n\n const changed = val !== this._serverAddress;\n\n this._serverAddress = val;\n\n this.onNetworkChange();\n\n if (changed) {\n events.trigger(this, 'serveraddresschanged');\n }\n }\n\n return this._serverAddress;\n }\n\n onNetworkChange() {\n this.lastDetectedBitrate = 0;\n this.lastDetectedBitrateTime = 0;\n setSavedEndpointInfo(this, null);\n\n redetectBitrate(this);\n }\n\n /**\n * Creates an api url based on a handler name and query string parameters\n * @param {String} name\n * @param {Object} params\n */\n getUrl(name, params, serverAddress) {\n if (!name) {\n throw new Error('Url name cannot be empty');\n }\n\n let url = serverAddress || this._serverAddress;\n\n if (!url) {\n throw new Error('serverAddress is yet not set');\n }\n\n if (name.charAt(0) !== '/') {\n url += '/';\n }\n\n url += name;\n\n if (params) {\n params = paramsToString(params);\n if (params) {\n url += `?${params}`;\n }\n }\n\n return url;\n }\n\n fetchWithFailover(request, enableReconnection) {\n console.log(`Requesting ${request.url}`);\n\n request.timeout = 30000;\n const instance = this;\n\n return getFetchPromise(request)\n .then((response) => {\n instance.lastFetch = new Date().getTime();\n\n if (response.status < 400) {\n if (request.dataType === 'json' || request.headers.accept === 'application/json') {\n return response.json();\n } else if (\n request.dataType === 'text' ||\n (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0\n ) {\n return response.text();\n } else {\n return response;\n }\n } else {\n onFetchFail(instance, request.url, response);\n return Promise.reject(response);\n }\n })\n .catch((error) => {\n if (error) {\n console.log(`Request failed to ${request.url} ${error.toString()}`);\n } else {\n console.log(`Request timed out to ${request.url}`);\n }\n\n // http://api.jquery.com/jQuery.ajax/\n if ((!error || !error.status) && enableReconnection) {\n console.log('Attempting reconnection');\n\n const previousServerAddress = instance.serverAddress();\n\n return tryReconnect(instance)\n .then(() => {\n console.log('Reconnect succeesed');\n request.url = request.url.replace(previousServerAddress, instance.serverAddress());\n\n return instance.fetchWithFailover(request, false);\n })\n .catch((innerError) => {\n console.log('Reconnect failed');\n onFetchFail(instance, request.url, {});\n throw innerError;\n });\n } else {\n console.log('Reporting request failure');\n\n onFetchFail(instance, request.url, {});\n throw error;\n }\n });\n }\n\n /**\n * Wraps around jQuery ajax methods to add additional info to the request.\n */\n fetch(request, includeAuthorization) {\n if (!request) {\n return Promise.reject('Request cannot be null');\n }\n\n request.headers = request.headers || {};\n\n if (includeAuthorization !== false) {\n this.setRequestHeaders(request.headers);\n }\n\n if (this.enableAutomaticNetworking === false || request.type !== 'GET') {\n console.log(`Requesting url without automatic networking: ${request.url}`);\n\n const instance = this;\n return getFetchPromise(request)\n .then((response) => {\n instance.lastFetch = new Date().getTime();\n\n if (response.status < 400) {\n if (request.dataType === 'json' || request.headers.accept === 'application/json') {\n return response.json();\n } else if (\n request.dataType === 'text' ||\n (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0\n ) {\n return response.text();\n } else {\n return response;\n }\n } else {\n onFetchFail(instance, request.url, response);\n return Promise.reject(response);\n }\n })\n .catch((error) => {\n onFetchFail(instance, request.url, {});\n return Promise.reject(error);\n });\n }\n\n return this.fetchWithFailover(request, true);\n }\n\n setAuthenticationInfo(accessKey, userId) {\n this._currentUser = null;\n\n this._serverInfo.AccessToken = accessKey;\n this._serverInfo.UserId = userId;\n redetectBitrate(this);\n }\n\n serverInfo(info) {\n if (info) {\n this._serverInfo = info;\n }\n\n return this._serverInfo;\n }\n\n /**\n * Gets or sets the current user id.\n */\n getCurrentUserId() {\n return this._serverInfo.UserId;\n }\n\n accessToken() {\n return this._serverInfo.AccessToken;\n }\n\n serverId() {\n return this.serverInfo().Id;\n }\n\n serverName() {\n return this.serverInfo().Name;\n }\n\n /**\n * Wraps around jQuery ajax methods to add additional info to the request.\n */\n ajax(request, includeAuthorization) {\n if (!request) {\n return Promise.reject('Request cannot be null');\n }\n\n return this.fetch(request, includeAuthorization);\n }\n\n /**\n * Gets or sets the current user id.\n */\n getCurrentUser(enableCache) {\n if (this._currentUser) {\n return Promise.resolve(this._currentUser);\n }\n\n const userId = this.getCurrentUserId();\n\n if (!userId) {\n return Promise.reject();\n }\n\n const instance = this;\n let user;\n\n const serverPromise = this.getUser(userId)\n .then((userObject) => {\n appStorage.setItem(`user-${userObject.Id}-${userObject.ServerId}`, JSON.stringify(userObject));\n\n instance._currentUser = userObject;\n return userObject;\n })\n .catch((response) => {\n // if timed out, look for cached value\n if (!response.status) {\n if (userId && instance.accessToken()) {\n user = getCachedUser(instance, userId);\n if (user) {\n return Promise.resolve(user);\n }\n }\n }\n\n throw response;\n });\n\n if (!this.lastFetch && enableCache !== false) {\n user = getCachedUser(instance, userId);\n if (user) {\n return Promise.resolve(user);\n }\n }\n\n return serverPromise;\n }\n\n isLoggedIn() {\n const info = this.serverInfo();\n if (info) {\n if (info.UserId && info.AccessToken) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Logout current user\n */\n logout() {\n stopBitrateDetection(this);\n this.closeWebSocket();\n\n const done = () => {\n const info = this.serverInfo();\n if (info && info.UserId && info.Id) {\n appStorage.removeItem(`user-${info.UserId}-${info.Id}`);\n }\n this.setAuthenticationInfo(null, null);\n };\n\n if (this.accessToken()) {\n const url = this.getUrl('Sessions/Logout');\n\n return this.ajax({\n type: 'POST',\n url\n }).then(done, done);\n }\n\n done();\n return Promise.resolve();\n }\n\n /**\n * Authenticates a user\n * @param {String} name\n * @param {String} password\n */\n authenticateUserByName(name, password) {\n if (!name) {\n return Promise.reject();\n }\n\n const url = this.getUrl('Users/authenticatebyname');\n\n return new Promise((resolve, reject) => {\n const postData = {\n Username: name,\n Pw: password || ''\n };\n\n this.ajax({\n type: 'POST',\n url: url,\n data: JSON.stringify(postData),\n dataType: 'json',\n contentType: 'application/json'\n })\n .then((result) => {\n const afterOnAuthenticated = () => {\n redetectBitrate(this);\n resolve(result);\n };\n\n if (this.onAuthenticated) {\n this.onAuthenticated(this, result).then(afterOnAuthenticated);\n } else {\n afterOnAuthenticated();\n }\n })\n .catch(reject);\n });\n }\n\n ensureWebSocket() {\n if (this.isWebSocketOpenOrConnecting() || !this.isWebSocketSupported()) {\n return;\n }\n\n try {\n this.openWebSocket();\n } catch (err) {\n console.log(`Error opening web socket: ${err}`);\n }\n }\n\n openWebSocket() {\n const accessToken = this.accessToken();\n\n if (!accessToken) {\n throw new Error('Cannot open web socket without access token.');\n }\n\n let url = this.getUrl('socket');\n\n url = replaceAll(url, 'emby/socket', 'embywebsocket');\n url = replaceAll(url, 'https:', 'wss:');\n url = replaceAll(url, 'http:', 'ws:');\n\n url += `?api_key=${accessToken}`;\n url += `&deviceId=${this.deviceId()}`;\n\n console.log(`opening web socket with url: ${url}`);\n\n const webSocket = new WebSocket(url);\n\n webSocket.onmessage = onWebSocketMessage.bind(this);\n webSocket.onopen = onWebSocketOpen.bind(this);\n webSocket.onerror = onWebSocketError.bind(this);\n setSocketOnClose(this, webSocket);\n\n this._webSocket = webSocket;\n }\n\n closeWebSocket() {\n const socket = this._webSocket;\n\n if (socket && socket.readyState === WebSocket.OPEN) {\n socket.close();\n }\n }\n\n sendWebSocketMessage(name, data) {\n console.log(`Sending web socket message: ${name}`);\n\n let msg = { MessageType: name };\n\n if (data) {\n msg.Data = data;\n }\n\n msg = JSON.stringify(msg);\n\n this._webSocket.send(msg);\n }\n\n sendMessage(name, data) {\n if (this.isWebSocketOpen()) {\n this.sendWebSocketMessage(name, data);\n }\n }\n\n isMessageChannelOpen() {\n return this.isWebSocketOpen();\n }\n\n isWebSocketOpen() {\n const socket = this._webSocket;\n\n if (socket) {\n return socket.readyState === WebSocket.OPEN;\n }\n return false;\n }\n\n isWebSocketOpenOrConnecting() {\n const socket = this._webSocket;\n\n if (socket) {\n return socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING;\n }\n return false;\n }\n\n get(url) {\n return this.ajax({\n type: 'GET',\n url\n });\n }\n\n getJSON(url, includeAuthorization) {\n return this.fetch(\n {\n url,\n type: 'GET',\n dataType: 'json',\n headers: {\n accept: 'application/json'\n }\n },\n includeAuthorization\n );\n }\n\n updateServerInfo(server, serverUrl) {\n if (server == null) {\n throw new Error('server cannot be null');\n }\n\n this.serverInfo(server);\n\n if (!serverUrl) {\n throw new Error(`serverUrl cannot be null. serverInfo: ${JSON.stringify(server)}`);\n }\n console.log(`Setting server address to ${serverUrl}`);\n this.serverAddress(serverUrl);\n }\n\n isWebSocketSupported() {\n try {\n return WebSocket != null;\n } catch (err) {\n return false;\n }\n }\n\n clearAuthenticationInfo() {\n this.setAuthenticationInfo(null, null);\n }\n\n encodeName(name) {\n name = name.split('/').join('-');\n name = name.split('&').join('-');\n name = name.split('?').join('-');\n\n const val = paramsToString({ name });\n return val.substring(val.indexOf('=') + 1).replace(\"'\", '%27');\n }\n\n /**\n * Gets the server time as a UTC formatted string.\n * @returns {Promise} Promise that it's fulfilled on request completion.\n * @since 10.6.0\n */\n getServerTime() {\n const url = this.getUrl('GetUTCTime');\n\n return this.ajax({\n type: 'GET',\n url: url\n });\n }\n\n getDownloadSpeed(byteSize) {\n const url = this.getUrl('Playback/BitrateTest', {\n Size: byteSize\n });\n\n const now = new Date().getTime();\n\n return this.ajax({\n type: 'GET',\n url,\n timeout: 5000\n }).then(() => {\n const responseTimeSeconds = (new Date().getTime() - now) / 1000;\n const bytesPerSecond = byteSize / responseTimeSeconds;\n const bitrate = Math.round(bytesPerSecond * 8);\n\n return bitrate;\n });\n }\n\n detectBitrate(force) {\n if (\n !force &&\n this.lastDetectedBitrate &&\n new Date().getTime() - (this.lastDetectedBitrateTime || 0) <= 3600000\n ) {\n return Promise.resolve(this.lastDetectedBitrate);\n }\n\n const instance = this;\n\n return this.getEndpointInfo().then(\n (info) => detectBitrateWithEndpointInfo(instance, info),\n (info) => detectBitrateWithEndpointInfo(instance, {})\n );\n }\n\n /**\n * Gets an item from the server\n * Omit itemId to get the root folder.\n */\n getItem(userId, itemId) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = userId ? this.getUrl(`Users/${userId}/Items/${itemId}`) : this.getUrl(`Items/${itemId}`);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the root folder from the server\n */\n getRootFolder(userId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n const url = this.getUrl(`Users/${userId}/Items/Root`);\n\n return this.getJSON(url);\n }\n\n getNotificationSummary(userId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n const url = this.getUrl(`Notifications/${userId}/Summary`);\n\n return this.getJSON(url);\n }\n\n getNotifications(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n const url = this.getUrl(`Notifications/${userId}`, options || {});\n\n return this.getJSON(url);\n }\n\n markNotificationsRead(userId, idList, isRead) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!idList) {\n throw new Error('null idList');\n }\n\n const suffix = isRead ? 'Read' : 'Unread';\n\n const params = {\n UserId: userId,\n Ids: idList.join(',')\n };\n\n const url = this.getUrl(`Notifications/${userId}/${suffix}`, params);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n getRemoteImageProviders(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n const urlPrefix = getRemoteImagePrefix(this, options);\n\n const url = this.getUrl(`${urlPrefix}/RemoteImages/Providers`, options);\n\n return this.getJSON(url);\n }\n\n getAvailableRemoteImages(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n const urlPrefix = getRemoteImagePrefix(this, options);\n\n const url = this.getUrl(`${urlPrefix}/RemoteImages`, options);\n\n return this.getJSON(url);\n }\n\n downloadRemoteImage(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n const urlPrefix = getRemoteImagePrefix(this, options);\n\n const url = this.getUrl(`${urlPrefix}/RemoteImages/Download`, options);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n getRecordingFolders(userId) {\n const url = this.getUrl('LiveTv/Recordings/Folders', { userId: userId });\n\n return this.getJSON(url);\n }\n\n getLiveTvInfo(options) {\n const url = this.getUrl('LiveTv/Info', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvGuideInfo(options) {\n const url = this.getUrl('LiveTv/GuideInfo', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvChannel(id, userId) {\n if (!id) {\n throw new Error('null id');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`LiveTv/Channels/${id}`, options);\n\n return this.getJSON(url);\n }\n\n getLiveTvChannels(options) {\n const url = this.getUrl('LiveTv/Channels', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvPrograms(options = {}) {\n if (options.channelIds && options.channelIds.length > 1800) {\n return this.ajax({\n type: 'POST',\n url: this.getUrl('LiveTv/Programs'),\n data: JSON.stringify(options),\n contentType: 'application/json',\n dataType: 'json'\n });\n } else {\n return this.ajax({\n type: 'GET',\n url: this.getUrl('LiveTv/Programs', options),\n dataType: 'json'\n });\n }\n }\n\n getLiveTvRecommendedPrograms(options = {}) {\n return this.ajax({\n type: 'GET',\n url: this.getUrl('LiveTv/Programs/Recommended', options),\n dataType: 'json'\n });\n }\n\n getLiveTvRecordings(options) {\n const url = this.getUrl('LiveTv/Recordings', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvRecordingSeries(options) {\n const url = this.getUrl('LiveTv/Recordings/Series', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvRecordingGroups(options) {\n const url = this.getUrl('LiveTv/Recordings/Groups', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvRecordingGroup(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/Recordings/Groups/${id}`);\n\n return this.getJSON(url);\n }\n\n getLiveTvRecording(id, userId) {\n if (!id) {\n throw new Error('null id');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`LiveTv/Recordings/${id}`, options);\n\n return this.getJSON(url);\n }\n\n getLiveTvProgram(id, userId) {\n if (!id) {\n throw new Error('null id');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`LiveTv/Programs/${id}`, options);\n\n return this.getJSON(url);\n }\n\n deleteLiveTvRecording(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/Recordings/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n cancelLiveTvTimer(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/Timers/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n getLiveTvTimers(options) {\n const url = this.getUrl('LiveTv/Timers', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvTimer(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/Timers/${id}`);\n\n return this.getJSON(url);\n }\n\n getNewLiveTvTimerDefaults(options = {}) {\n const url = this.getUrl('LiveTv/Timers/Defaults', options);\n\n return this.getJSON(url);\n }\n\n createLiveTvTimer(item) {\n if (!item) {\n throw new Error('null item');\n }\n\n const url = this.getUrl('LiveTv/Timers');\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(item),\n contentType: 'application/json'\n });\n }\n\n updateLiveTvTimer(item) {\n if (!item) {\n throw new Error('null item');\n }\n\n const url = this.getUrl(`LiveTv/Timers/${item.Id}`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(item),\n contentType: 'application/json'\n });\n }\n\n resetLiveTvTuner(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/Tuners/${id}/Reset`);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n getLiveTvSeriesTimers(options) {\n const url = this.getUrl('LiveTv/SeriesTimers', options || {});\n\n return this.getJSON(url);\n }\n\n getLiveTvSeriesTimer(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/SeriesTimers/${id}`);\n\n return this.getJSON(url);\n }\n\n cancelLiveTvSeriesTimer(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`LiveTv/SeriesTimers/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n createLiveTvSeriesTimer(item) {\n if (!item) {\n throw new Error('null item');\n }\n\n const url = this.getUrl('LiveTv/SeriesTimers');\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(item),\n contentType: 'application/json'\n });\n }\n\n updateLiveTvSeriesTimer(item) {\n if (!item) {\n throw new Error('null item');\n }\n\n const url = this.getUrl(`LiveTv/SeriesTimers/${item.Id}`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(item),\n contentType: 'application/json'\n });\n }\n\n getRegistrationInfo(feature) {\n const url = this.getUrl(`Registrations/${feature}`);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the current server status\n */\n getSystemInfo(itemId) {\n const url = this.getUrl('System/Info');\n\n const instance = this;\n\n return this.getJSON(url).then((info) => {\n instance.setSystemInfo(info);\n return Promise.resolve(info);\n });\n }\n\n getSyncStatus() {\n const url = this.getUrl('Sync/' + itemId + '/Status');\n\n return this.ajax({\n url: url,\n type: 'POST',\n dataType: 'json',\n contentType: 'application/json',\n data: JSON.stringify({\n TargetId: this.deviceId()\n })\n });\n }\n\n /**\n * Gets the current server status\n */\n getPublicSystemInfo() {\n const url = this.getUrl('System/Info/Public');\n\n const instance = this;\n\n return this.getJSON(url).then((info) => {\n instance.setSystemInfo(info);\n return Promise.resolve(info);\n });\n }\n\n getInstantMixFromItem(itemId, options) {\n const url = this.getUrl(`Items/${itemId}/InstantMix`, options);\n\n return this.getJSON(url);\n }\n\n getEpisodes(itemId, options) {\n const url = this.getUrl(`Shows/${itemId}/Episodes`, options);\n\n return this.getJSON(url);\n }\n\n getDisplayPreferences(id, userId, app) {\n const url = this.getUrl(`DisplayPreferences/${id}`, {\n userId,\n client: app\n });\n\n return this.getJSON(url);\n }\n\n updateDisplayPreferences(id, obj, userId, app) {\n const url = this.getUrl(`DisplayPreferences/${id}`, {\n userId,\n client: app\n });\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(obj),\n contentType: 'application/json'\n });\n }\n\n getSeasons(itemId, options) {\n const url = this.getUrl(`Shows/${itemId}/Seasons`, options);\n\n return this.getJSON(url);\n }\n\n getSimilarItems(itemId, options) {\n const url = this.getUrl(`Items/${itemId}/Similar`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets all cultures known to the server\n */\n getCultures() {\n const url = this.getUrl('Localization/cultures');\n\n return this.getJSON(url);\n }\n\n /**\n * Gets all countries known to the server\n */\n getCountries() {\n const url = this.getUrl('Localization/countries');\n\n return this.getJSON(url);\n }\n\n getPlaybackInfo(itemId, options, deviceProfile) {\n const postData = {\n DeviceProfile: deviceProfile\n };\n\n return this.ajax({\n url: this.getUrl(`Items/${itemId}/PlaybackInfo`, options),\n type: 'POST',\n data: JSON.stringify(postData),\n contentType: 'application/json',\n dataType: 'json'\n });\n }\n\n getLiveStreamMediaInfo(liveStreamId) {\n const postData = {\n LiveStreamId: liveStreamId\n };\n\n return this.ajax({\n url: this.getUrl('LiveStreams/MediaInfo'),\n type: 'POST',\n data: JSON.stringify(postData),\n contentType: 'application/json',\n dataType: 'json'\n });\n }\n\n getIntros(itemId) {\n return this.getJSON(this.getUrl(`Users/${this.getCurrentUserId()}/Items/${itemId}/Intros`));\n }\n\n /**\n * Gets the directory contents of a path on the server\n */\n getDirectoryContents(path, options) {\n if (!path) {\n throw new Error('null path');\n }\n if (typeof path !== 'string') {\n throw new Error('invalid path');\n }\n\n options = options || {};\n\n options.path = path;\n\n const url = this.getUrl('Environment/DirectoryContents', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets shares from a network device\n */\n getNetworkShares(path) {\n if (!path) {\n throw new Error('null path');\n }\n\n const options = {};\n options.path = path;\n\n const url = this.getUrl('Environment/NetworkShares', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the parent of a given path\n */\n getParentPath(path) {\n if (!path) {\n throw new Error('null path');\n }\n\n const options = {};\n options.path = path;\n\n const url = this.getUrl('Environment/ParentPath', options);\n\n return this.ajax({\n type: 'GET',\n url,\n dataType: 'text'\n });\n }\n\n /**\n * Gets a list of physical drives from the server\n */\n getDrives() {\n const url = this.getUrl('Environment/Drives');\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a list of network devices from the server\n */\n getNetworkDevices() {\n const url = this.getUrl('Environment/NetworkDevices');\n\n return this.getJSON(url);\n }\n\n /**\n * Cancels a package installation\n */\n cancelPackageInstallation(installationId) {\n if (!installationId) {\n throw new Error('null installationId');\n }\n\n const url = this.getUrl(`Packages/Installing/${installationId}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Refreshes metadata for an item\n */\n refreshItem(itemId, options) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Items/${itemId}/Refresh`, options || {});\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Installs or updates a new plugin\n */\n installPlugin(name, guid, version) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {\n AssemblyGuid: guid\n };\n\n if (version) {\n options.version = version;\n }\n\n const url = this.getUrl(`Packages/Installed/${name}`, options);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Instructs the server to perform a restart.\n */\n restartServer() {\n const url = this.getUrl('System/Restart');\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Instructs the server to perform a shutdown.\n */\n shutdownServer() {\n const url = this.getUrl('System/Shutdown');\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Gets information about an installable package\n */\n getPackageInfo(name, guid) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {\n AssemblyGuid: guid\n };\n\n const url = this.getUrl(`Packages/${name}`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the virtual folder list\n */\n getVirtualFolders() {\n let url = 'Library/VirtualFolders';\n\n url = this.getUrl(url);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets all the paths of the locations in the physical root.\n */\n getPhysicalPaths() {\n const url = this.getUrl('Library/PhysicalPaths');\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the current server configuration\n */\n getServerConfiguration() {\n const url = this.getUrl('System/Configuration');\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the current server configuration\n */\n getDevicesOptions() {\n const url = this.getUrl('System/Configuration/devices');\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the current server configuration\n */\n getContentUploadHistory() {\n const url = this.getUrl('Devices/CameraUploads', {\n DeviceId: this.deviceId()\n });\n\n return this.getJSON(url);\n }\n\n getNamedConfiguration(name) {\n const url = this.getUrl(`System/Configuration/${name}`);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets the server's scheduled tasks\n */\n getScheduledTasks(options = {}) {\n const url = this.getUrl('ScheduledTasks', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Starts a scheduled task\n */\n startScheduledTask(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`ScheduledTasks/Running/${id}`);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Gets a scheduled task\n */\n getScheduledTask(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`ScheduledTasks/${id}`);\n\n return this.getJSON(url);\n }\n\n getNextUpEpisodes(options) {\n const url = this.getUrl('Shows/NextUp', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Stops a scheduled task\n */\n stopScheduledTask(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`ScheduledTasks/Running/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Gets the configuration of a plugin\n * @param {String} Id\n */\n getPluginConfiguration(id) {\n if (!id) {\n throw new Error('null Id');\n }\n\n const url = this.getUrl(`Plugins/${id}/Configuration`);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a list of plugins that are available to be installed\n */\n getAvailablePlugins(options = {}) {\n options.PackageType = 'UserInstalled';\n\n const url = this.getUrl('Packages', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Uninstalls a plugin\n * @param {String} Id\n */\n uninstallPlugin(id) {\n if (!id) {\n throw new Error('null Id');\n }\n\n const url = this.getUrl(`Plugins/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Removes a virtual folder\n * @param {String} name\n */\n removeVirtualFolder(name, refreshLibrary) {\n if (!name) {\n throw new Error('null name');\n }\n\n let url = 'Library/VirtualFolders';\n\n url = this.getUrl(url, {\n refreshLibrary: refreshLibrary ? true : false,\n name\n });\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Adds a virtual folder\n * @param {String} name\n */\n addVirtualFolder(name, type, refreshLibrary, libraryOptions) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (type) {\n options.collectionType = type;\n }\n\n options.refreshLibrary = refreshLibrary ? true : false;\n options.name = name;\n\n let url = 'Library/VirtualFolders';\n\n url = this.getUrl(url, options);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify({\n LibraryOptions: libraryOptions\n }),\n contentType: 'application/json'\n });\n }\n\n updateVirtualFolderOptions(id, libraryOptions) {\n if (!id) {\n throw new Error('null name');\n }\n\n let url = 'Library/VirtualFolders/LibraryOptions';\n\n url = this.getUrl(url);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify({\n Id: id,\n LibraryOptions: libraryOptions\n }),\n contentType: 'application/json'\n });\n }\n\n /**\n * Renames a virtual folder\n * @param {String} name\n */\n renameVirtualFolder(name, newName, refreshLibrary) {\n if (!name) {\n throw new Error('null name');\n }\n\n let url = 'Library/VirtualFolders/Name';\n\n url = this.getUrl(url, {\n refreshLibrary: refreshLibrary ? true : false,\n newName,\n name\n });\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Adds an additional mediaPath to an existing virtual folder\n * @param {String} name\n */\n addMediaPath(virtualFolderName, mediaPath, networkSharePath, refreshLibrary) {\n if (!virtualFolderName) {\n throw new Error('null virtualFolderName');\n }\n\n if (!mediaPath) {\n throw new Error('null mediaPath');\n }\n\n let url = 'Library/VirtualFolders/Paths';\n\n const pathInfo = {\n Path: mediaPath\n };\n if (networkSharePath) {\n pathInfo.NetworkPath = networkSharePath;\n }\n\n url = this.getUrl(url, {\n refreshLibrary: refreshLibrary ? true : false\n });\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify({\n Name: virtualFolderName,\n PathInfo: pathInfo\n }),\n contentType: 'application/json'\n });\n }\n\n updateMediaPath(virtualFolderName, pathInfo) {\n if (!virtualFolderName) {\n throw new Error('null virtualFolderName');\n }\n\n if (!pathInfo) {\n throw new Error('null pathInfo');\n }\n\n let url = 'Library/VirtualFolders/Paths/Update';\n\n url = this.getUrl(url);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify({\n Name: virtualFolderName,\n PathInfo: pathInfo\n }),\n contentType: 'application/json'\n });\n }\n\n /**\n * Removes a media path from a virtual folder\n * @param {String} name\n */\n removeMediaPath(virtualFolderName, mediaPath, refreshLibrary) {\n if (!virtualFolderName) {\n throw new Error('null virtualFolderName');\n }\n\n if (!mediaPath) {\n throw new Error('null mediaPath');\n }\n\n let url = 'Library/VirtualFolders/Paths';\n\n url = this.getUrl(url, {\n refreshLibrary: refreshLibrary ? true : false,\n path: mediaPath,\n name: virtualFolderName\n });\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Deletes a user\n * @param {String} id\n */\n deleteUser(id) {\n if (!id) {\n throw new Error('null id');\n }\n\n const url = this.getUrl(`Users/${id}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Deletes a user image\n * @param {String} userId\n * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.\n */\n deleteUserImage(userId, imageType, imageIndex) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!imageType) {\n throw new Error('null imageType');\n }\n\n let url = this.getUrl(`Users/${userId}/Images/${imageType}`);\n\n if (imageIndex != null) {\n url += `/${imageIndex}`;\n }\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n deleteItemImage(itemId, imageType, imageIndex) {\n if (!imageType) {\n throw new Error('null imageType');\n }\n\n let url = this.getUrl(`Items/${itemId}/Images`);\n\n url += `/${imageType}`;\n\n if (imageIndex != null) {\n url += `/${imageIndex}`;\n }\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n deleteItem(itemId) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Items/${itemId}`);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n stopActiveEncodings(playSessionId) {\n const options = {\n deviceId: this.deviceId()\n };\n\n if (playSessionId) {\n options.PlaySessionId = playSessionId;\n }\n\n const url = this.getUrl('Videos/ActiveEncodings', options);\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n reportCapabilities(options) {\n const url = this.getUrl('Sessions/Capabilities/Full');\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(options),\n contentType: 'application/json'\n });\n }\n\n updateItemImageIndex(itemId, imageType, imageIndex, newIndex) {\n if (!imageType) {\n throw new Error('null imageType');\n }\n\n const options = { newIndex };\n\n const url = this.getUrl(`Items/${itemId}/Images/${imageType}/${imageIndex}/Index`, options);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n getItemImageInfos(itemId) {\n const url = this.getUrl(`Items/${itemId}/Images`);\n\n return this.getJSON(url);\n }\n\n getCriticReviews(itemId, options) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Items/${itemId}/CriticReviews`, options);\n\n return this.getJSON(url);\n }\n\n getItemDownloadUrl(itemId) {\n if (!itemId) {\n throw new Error('itemId cannot be empty');\n }\n\n const url = `Items/${itemId}/Download`;\n\n return this.getUrl(url, {\n api_key: this.accessToken()\n });\n }\n\n getSessions(options) {\n const url = this.getUrl('Sessions', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Uploads a user image\n * @param {String} userId\n * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.\n * @param {Object} file The file from the input element\n */\n uploadUserImage(userId, imageType, file) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!imageType) {\n throw new Error('null imageType');\n }\n\n if (!file) {\n throw new Error('File must be an image.');\n }\n\n if (!file.type.startsWith('image/')) {\n throw new Error('File must be an image.');\n }\n\n const instance = this;\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onerror = () => {\n reject();\n };\n\n reader.onabort = () => {\n reject();\n };\n\n // Closure to capture the file information.\n reader.onload = (e) => {\n // Split by a comma to remove the url: prefix\n const data = e.target.result.split(',')[1];\n\n const url = instance.getUrl(`Users/${userId}/Images/${imageType}`);\n\n instance\n .ajax({\n type: 'POST',\n url,\n data,\n contentType: `image/${file.name.substring(file.name.lastIndexOf('.') + 1)}`\n })\n .then(resolve, reject);\n };\n\n // Read in the image file as a data URL.\n reader.readAsDataURL(file);\n });\n }\n\n uploadItemImage(itemId, imageType, file) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n if (!imageType) {\n throw new Error('null imageType');\n }\n\n if (!file) {\n throw new Error('File must be an image.');\n }\n\n if (!file.type.startsWith('image/')) {\n throw new Error('File must be an image.');\n }\n\n let url = this.getUrl(`Items/${itemId}/Images`);\n\n url += `/${imageType}`;\n const instance = this;\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onerror = () => {\n reject();\n };\n\n reader.onabort = () => {\n reject();\n };\n\n // Closure to capture the file information.\n reader.onload = (e) => {\n // Split by a comma to remove the url: prefix\n const data = e.target.result.split(',')[1];\n\n instance\n .ajax({\n type: 'POST',\n url,\n data,\n contentType: `image/${file.name.substring(file.name.lastIndexOf('.') + 1)}`\n })\n .then(resolve, reject);\n };\n\n // Read in the image file as a data URL.\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Gets the list of installed plugins on the server\n */\n getInstalledPlugins() {\n const options = {};\n\n const url = this.getUrl('Plugins', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a user by id\n * @param {String} id\n */\n getUser(id) {\n if (!id) {\n throw new Error('Must supply a userId');\n }\n\n const url = this.getUrl(`Users/${id}`);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a studio\n */\n getStudio(name, userId) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Studios/${this.encodeName(name)}`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a genre\n */\n getGenre(name, userId) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Genres/${this.encodeName(name)}`, options);\n\n return this.getJSON(url);\n }\n\n getMusicGenre(name, userId) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`MusicGenres/${this.encodeName(name)}`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets an artist\n */\n getArtist(name, userId) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Artists/${this.encodeName(name)}`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets a Person\n */\n getPerson(name, userId) {\n if (!name) {\n throw new Error('null name');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Persons/${this.encodeName(name)}`, options);\n\n return this.getJSON(url);\n }\n\n getPublicUsers() {\n const url = this.getUrl('users/public');\n\n return this.ajax(\n {\n type: 'GET',\n url,\n dataType: 'json'\n },\n false\n );\n }\n\n /**\n * Gets all users from the server\n */\n getUsers(options) {\n const url = this.getUrl('users', options || {});\n\n return this.getJSON(url);\n }\n\n /**\n * Gets all available parental ratings from the server\n */\n getParentalRatings() {\n const url = this.getUrl('Localization/ParentalRatings');\n\n return this.getJSON(url);\n }\n\n getDefaultImageQuality(imageType) {\n return imageType.toLowerCase() === 'backdrop' ? 80 : 90;\n }\n\n /**\n * Constructs a url for a user image\n * @param {String} userId\n * @param {Object} options\n * Options supports the following properties:\n * width - download the image at a fixed width\n * height - download the image at a fixed height\n * maxWidth - download the image at a maxWidth\n * maxHeight - download the image at a maxHeight\n * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.\n * For best results do not specify both width and height together, as aspect ratio might be altered.\n */\n getUserImageUrl(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n\n let url = `Users/${userId}/Images/${options.type}`;\n\n if (options.index != null) {\n url += `/${options.index}`;\n }\n\n normalizeImageOptions(this, options);\n\n // Don't put these on the query string\n delete options.type;\n delete options.index;\n\n return this.getUrl(url, options);\n }\n\n /**\n * Constructs a url for an item image\n * @param {String} itemId\n * @param {Object} options\n * Options supports the following properties:\n * type - Primary, logo, backdrop, etc. See the server-side enum ImageType\n * index - When downloading a backdrop, use this to specify which one (omitting is equivalent to zero)\n * width - download the image at a fixed width\n * height - download the image at a fixed height\n * maxWidth - download the image at a maxWidth\n * maxHeight - download the image at a maxHeight\n * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.\n * For best results do not specify both width and height together, as aspect ratio might be altered.\n */\n getImageUrl(itemId, options) {\n if (!itemId) {\n throw new Error('itemId cannot be empty');\n }\n\n options = options || {};\n\n let url = `Items/${itemId}/Images/${options.type}`;\n\n if (options.index != null) {\n url += `/${options.index}`;\n }\n\n options.quality = options.quality || this.getDefaultImageQuality(options.type);\n\n if (this.normalizeImageOptions) {\n this.normalizeImageOptions(options);\n }\n\n // Don't put these on the query string\n delete options.type;\n delete options.index;\n\n return this.getUrl(url, options);\n }\n\n getScaledImageUrl(itemId, options) {\n if (!itemId) {\n throw new Error('itemId cannot be empty');\n }\n\n options = options || {};\n\n let url = `Items/${itemId}/Images/${options.type}`;\n\n if (options.index != null) {\n url += `/${options.index}`;\n }\n\n normalizeImageOptions(this, options);\n\n // Don't put these on the query string\n delete options.type;\n delete options.index;\n delete options.minScale;\n\n return this.getUrl(url, options);\n }\n\n getThumbImageUrl(item, options) {\n if (!item) {\n throw new Error('null item');\n }\n\n options = options || {};\n\n options.imageType = 'thumb';\n\n if (item.ImageTags && item.ImageTags.Thumb) {\n options.tag = item.ImageTags.Thumb;\n return this.getImageUrl(item.Id, options);\n } else if (item.ParentThumbItemId) {\n options.tag = item.ImageTags.ParentThumbImageTag;\n return this.getImageUrl(item.ParentThumbItemId, options);\n } else {\n return null;\n }\n }\n\n /**\n * Updates a user's password\n * @param {String} userId\n * @param {String} currentPassword\n * @param {String} newPassword\n */\n updateUserPassword(userId, currentPassword, newPassword) {\n if (!userId) {\n return Promise.reject();\n }\n\n const url = this.getUrl(`Users/${userId}/Password`);\n\n return this.ajax({\n type: 'POST',\n url: url,\n data: JSON.stringify({\n CurrentPw: currentPassword || '',\n NewPw: newPassword\n }),\n contentType: 'application/json'\n });\n }\n\n /**\n * Updates a user's easy password\n * @param {String} userId\n * @param {String} newPassword\n */\n updateEasyPassword(userId, newPassword) {\n if (!userId) {\n Promise.reject();\n return;\n }\n\n const url = this.getUrl(`Users/${userId}/EasyPassword`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: {\n NewPw: newPassword\n }\n });\n }\n\n /**\n * Resets a user's password\n * @param {String} userId\n */\n resetUserPassword(userId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n const url = this.getUrl(`Users/${userId}/Password`);\n\n const postData = {};\n\n postData.resetPassword = true;\n\n return this.ajax({\n type: 'POST',\n url,\n data: postData\n });\n }\n\n resetEasyPassword(userId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n const url = this.getUrl(`Users/${userId}/EasyPassword`);\n\n const postData = {};\n\n postData.resetPassword = true;\n\n return this.ajax({\n type: 'POST',\n url,\n data: postData\n });\n }\n\n /**\n * Updates the server's configuration\n * @param {Object} configuration\n */\n updateServerConfiguration(configuration) {\n if (!configuration) {\n throw new Error('null configuration');\n }\n\n const url = this.getUrl('System/Configuration');\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(configuration),\n contentType: 'application/json'\n });\n }\n\n updateNamedConfiguration(name, configuration) {\n if (!configuration) {\n throw new Error('null configuration');\n }\n\n const url = this.getUrl(`System/Configuration/${name}`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(configuration),\n contentType: 'application/json'\n });\n }\n\n updateItem(item) {\n if (!item) {\n throw new Error('null item');\n }\n\n const url = this.getUrl(`Items/${item.Id}`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(item),\n contentType: 'application/json'\n });\n }\n\n /**\n * Updates plugin security info\n */\n updatePluginSecurityInfo(info) {\n const url = this.getUrl('Plugins/SecurityInfo');\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(info),\n contentType: 'application/json'\n });\n }\n\n /**\n * Creates a user\n * @param {Object} user\n */\n createUser(user) {\n const url = this.getUrl('Users/New');\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(user),\n contentType: 'application/json',\n headers: {\n accept: 'application/json'\n }\n });\n }\n\n /**\n * Updates a user\n * @param {Object} user\n */\n updateUser(user) {\n if (!user) {\n throw new Error('null user');\n }\n\n const url = this.getUrl(`Users/${user.Id}`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(user),\n contentType: 'application/json'\n });\n }\n\n updateUserPolicy(userId, policy) {\n if (!userId) {\n throw new Error('null userId');\n }\n if (!policy) {\n throw new Error('null policy');\n }\n\n const url = this.getUrl(`Users/${userId}/Policy`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(policy),\n contentType: 'application/json'\n });\n }\n\n updateUserConfiguration(userId, configuration) {\n if (!userId) {\n throw new Error('null userId');\n }\n if (!configuration) {\n throw new Error('null configuration');\n }\n\n const url = this.getUrl(`Users/${userId}/Configuration`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(configuration),\n contentType: 'application/json'\n });\n }\n\n /**\n * Updates the Triggers for a ScheduledTask\n * @param {String} id\n * @param {Object} triggers\n */\n updateScheduledTaskTriggers(id, triggers) {\n if (!id) {\n throw new Error('null id');\n }\n\n if (!triggers) {\n throw new Error('null triggers');\n }\n\n const url = this.getUrl(`ScheduledTasks/${id}/Triggers`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(triggers),\n contentType: 'application/json'\n });\n }\n\n /**\n * Updates a plugin's configuration\n * @param {String} Id\n * @param {Object} configuration\n */\n updatePluginConfiguration(id, configuration) {\n if (!id) {\n throw new Error('null Id');\n }\n\n if (!configuration) {\n throw new Error('null configuration');\n }\n\n const url = this.getUrl(`Plugins/${id}/Configuration`);\n\n return this.ajax({\n type: 'POST',\n url,\n data: JSON.stringify(configuration),\n contentType: 'application/json'\n });\n }\n\n getAncestorItems(itemId, userId) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Items/${itemId}/Ancestors`, options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets items based on a query, typically for children of a folder\n * @param {String} userId\n * @param {Object} options\n * Options accepts the following properties:\n * itemId - Localize the search to a specific folder (root if omitted)\n * startIndex - Use for paging\n * limit - Use to limit results to a certain number of items\n * filter - Specify one or more ItemFilters, comma delimeted (see server-side enum)\n * sortBy - Specify an ItemSortBy (comma-delimeted list see server-side enum)\n * sortOrder - ascending/descending\n * fields - additional fields to include aside from basic info. This is a comma delimited list. See server-side enum ItemFields.\n * index - the name of the dynamic, localized index function\n * dynamicSortBy - the name of the dynamic localized sort function\n * recursive - Whether or not the query should be recursive\n * searchTerm - search term to use as a filter\n */\n getItems(userId, options) {\n let url;\n\n if ((typeof userId).toString().toLowerCase() === 'string') {\n url = this.getUrl(`Users/${userId}/Items`, options);\n } else {\n url = this.getUrl('Items', options);\n }\n\n return this.getJSON(url);\n }\n\n getResumableItems(userId, options) {\n if (this.isMinServerVersion('3.2.33')) {\n return this.getJSON(this.getUrl(`Users/${userId}/Items/Resume`, options));\n }\n\n return this.getItems(\n userId,\n Object.assign(\n {\n SortBy: 'DatePlayed',\n SortOrder: 'Descending',\n Filters: 'IsResumable',\n Recursive: true,\n CollapseBoxSetItems: false,\n ExcludeLocationTypes: 'Virtual'\n },\n options\n )\n );\n }\n\n getMovieRecommendations(options) {\n return this.getJSON(this.getUrl('Movies/Recommendations', options));\n }\n\n getUpcomingEpisodes(options) {\n return this.getJSON(this.getUrl('Shows/Upcoming', options));\n }\n\n getUserViews(options = {}, userId) {\n const url = this.getUrl(`Users/${userId || this.getCurrentUserId()}/Views`, options);\n\n return this.getJSON(url);\n }\n\n /**\n Gets artists from an item\n */\n getArtists(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('Artists', options);\n\n return this.getJSON(url);\n }\n\n /**\n Gets artists from an item\n */\n getAlbumArtists(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('Artists/AlbumArtists', options);\n\n return this.getJSON(url);\n }\n\n /**\n Gets genres from an item\n */\n getGenres(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('Genres', options);\n\n return this.getJSON(url);\n }\n\n getMusicGenres(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('MusicGenres', options);\n\n return this.getJSON(url);\n }\n\n /**\n Gets people from an item\n */\n getPeople(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('Persons', options);\n\n return this.getJSON(url);\n }\n\n /**\n Gets studios from an item\n */\n getStudios(userId, options) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n options = options || {};\n options.userId = userId;\n\n const url = this.getUrl('Studios', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Gets local trailers for an item\n */\n getLocalTrailers(userId, itemId) {\n if (!userId) {\n throw new Error('null userId');\n }\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/Items/${itemId}/LocalTrailers`);\n\n return this.getJSON(url);\n }\n\n getAdditionalVideoParts(userId, itemId) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl(`Videos/${itemId}/AdditionalParts`, options);\n\n return this.getJSON(url);\n }\n\n getThemeMedia(userId, itemId, inherit) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n options.InheritFromParent = inherit || false;\n\n const url = this.getUrl(`Items/${itemId}/ThemeMedia`, options);\n\n return this.getJSON(url);\n }\n\n getSearchHints(options) {\n const url = this.getUrl('Search/Hints', options);\n const serverId = this.serverId();\n\n return this.getJSON(url).then((result) => {\n result.SearchHints.forEach((i) => {\n i.ServerId = serverId;\n });\n return result;\n });\n }\n\n /**\n * Gets special features for an item\n */\n getSpecialFeatures(userId, itemId) {\n if (!userId) {\n throw new Error('null userId');\n }\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/Items/${itemId}/SpecialFeatures`);\n\n return this.getJSON(url);\n }\n\n getDateParamValue(date) {\n function formatDigit(i) {\n return i < 10 ? `0${i}` : i;\n }\n\n const d = date;\n\n return `${d.getFullYear()}${formatDigit(d.getMonth() + 1)}${formatDigit(d.getDate())}${formatDigit(\n d.getHours()\n )}${formatDigit(d.getMinutes())}${formatDigit(d.getSeconds())}`;\n }\n\n markPlayed(userId, itemId, date) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const options = {};\n\n if (date) {\n options.DatePlayed = this.getDateParamValue(date);\n }\n\n const url = this.getUrl(`Users/${userId}/PlayedItems/${itemId}`, options);\n\n return this.ajax({\n type: 'POST',\n url,\n dataType: 'json'\n });\n }\n\n markUnplayed(userId, itemId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/PlayedItems/${itemId}`);\n\n return this.ajax({\n type: 'DELETE',\n url,\n dataType: 'json'\n });\n }\n\n /**\n * Updates a user's favorite status for an item.\n * @param {String} userId\n * @param {String} itemId\n * @param {Boolean} isFavorite\n */\n updateFavoriteStatus(userId, itemId, isFavorite) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/FavoriteItems/${itemId}`);\n\n const method = isFavorite ? 'POST' : 'DELETE';\n\n return this.ajax({\n type: method,\n url,\n dataType: 'json'\n });\n }\n\n /**\n * Updates a user's personal rating for an item\n * @param {String} userId\n * @param {String} itemId\n * @param {Boolean} likes\n */\n updateUserItemRating(userId, itemId, likes) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/Items/${itemId}/Rating`, {\n likes\n });\n\n return this.ajax({\n type: 'POST',\n url,\n dataType: 'json'\n });\n }\n\n getItemCounts(userId) {\n const options = {};\n\n if (userId) {\n options.userId = userId;\n }\n\n const url = this.getUrl('Items/Counts', options);\n\n return this.getJSON(url);\n }\n\n /**\n * Clears a user's personal rating for an item\n * @param {String} userId\n * @param {String} itemId\n */\n clearUserItemRating(userId, itemId) {\n if (!userId) {\n throw new Error('null userId');\n }\n\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n const url = this.getUrl(`Users/${userId}/Items/${itemId}/Rating`);\n\n return this.ajax({\n type: 'DELETE',\n url,\n dataType: 'json'\n });\n }\n\n /**\n * Reports the user has started playing something\n * @param {String} userId\n * @param {String} itemId\n */\n reportPlaybackStart(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n this.lastPlaybackProgressReport = 0;\n this.lastPlaybackProgressReportTicks = null;\n stopBitrateDetection(this);\n\n cancelReportPlaybackProgressPromise(this);\n const url = this.getUrl('Sessions/Playing');\n\n return this.ajax({\n type: 'POST',\n data: JSON.stringify(options),\n contentType: 'application/json',\n url\n });\n }\n\n /**\n * Reports progress viewing an item\n * @param {String} userId\n * @param {String} itemId\n */\n reportPlaybackProgress(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n const eventName = options.EventName || 'timeupdate';\n let reportRateLimitTime = reportRateLimits[eventName] || 0;\n\n const now = new Date().getTime();\n const msSinceLastReport = now - (this.lastPlaybackProgressReport || 0);\n const newPositionTicks = options.PositionTicks;\n\n if (msSinceLastReport < reportRateLimitTime && eventName === 'timeupdate' && newPositionTicks) {\n const expectedReportTicks = 1e4 * msSinceLastReport + (this.lastPlaybackProgressReportTicks || 0);\n if (Math.abs(newPositionTicks - expectedReportTicks) >= 5e7) reportRateLimitTime = 0;\n }\n\n if (\n reportRateLimitTime <\n (this.reportPlaybackProgressTimeout !== undefined ? this.reportPlaybackProgressTimeout : 1e6)\n ) {\n cancelReportPlaybackProgressPromise(this);\n }\n\n this.lastPlaybackProgressOptions = options;\n\n /* eslint-disable-next-line @typescript-eslint/no-misused-promises */\n if (this.reportPlaybackProgressPromise) return Promise.resolve();\n\n let instance = this;\n let promise;\n let cancelled = false;\n\n let resetPromise = function () {\n if (instance.reportPlaybackProgressPromise !== promise) return;\n\n delete instance.lastPlaybackProgressOptions;\n delete instance.reportPlaybackProgressTimeout;\n delete instance.reportPlaybackProgressPromise;\n delete instance.reportPlaybackProgressCancel;\n };\n\n let sendReport = function (lastOptions) {\n resetPromise();\n\n if (!lastOptions) throw new Error('null options');\n\n instance.lastPlaybackProgressReport = new Date().getTime();\n instance.lastPlaybackProgressReportTicks = lastOptions.PositionTicks;\n\n const url = instance.getUrl('Sessions/Playing/Progress');\n return instance.ajax({\n type: 'POST',\n data: JSON.stringify(lastOptions),\n contentType: 'application/json',\n url: url\n });\n };\n\n let delay = Math.max(0, reportRateLimitTime - msSinceLastReport);\n\n promise = new Promise((resolve, reject) => setTimeout(resolve, delay))\n .then(() => {\n if (cancelled) return Promise.resolve();\n return sendReport(instance.lastPlaybackProgressOptions);\n })\n .finally(() => {\n resetPromise();\n });\n\n this.reportPlaybackProgressTimeout = reportRateLimitTime;\n this.reportPlaybackProgressPromise = promise;\n this.reportPlaybackProgressCancel = function () {\n cancelled = true;\n resetPromise();\n };\n\n return promise;\n }\n\n reportOfflineActions(actions) {\n if (!actions) {\n throw new Error('null actions');\n }\n\n const url = this.getUrl('Sync/OfflineActions');\n\n return this.ajax({\n type: 'POST',\n data: JSON.stringify(actions),\n contentType: 'application/json',\n url\n });\n }\n\n syncData(data) {\n if (!data) {\n throw new Error('null data');\n }\n\n const url = this.getUrl('Sync/Data');\n\n return this.ajax({\n type: 'POST',\n data: JSON.stringify(data),\n contentType: 'application/json',\n url,\n dataType: 'json'\n });\n }\n\n getReadySyncItems(deviceId) {\n if (!deviceId) {\n throw new Error('null deviceId');\n }\n\n const url = this.getUrl('Sync/Items/Ready', {\n TargetId: deviceId\n });\n\n return this.getJSON(url);\n }\n\n reportSyncJobItemTransferred(syncJobItemId) {\n if (!syncJobItemId) {\n throw new Error('null syncJobItemId');\n }\n\n const url = this.getUrl(`Sync/JobItems/${syncJobItemId}/Transferred`);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n cancelSyncItems(itemIds, targetId) {\n if (!itemIds) {\n throw new Error('null itemIds');\n }\n\n const url = this.getUrl(`Sync/${targetId || this.deviceId()}/Items`, {\n ItemIds: itemIds.join(',')\n });\n\n return this.ajax({\n type: 'DELETE',\n url\n });\n }\n\n /**\n * Reports a user has stopped playing an item\n * @param {String} userId\n * @param {String} itemId\n */\n reportPlaybackStopped(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n this.lastPlaybackProgressReport = 0;\n this.lastPlaybackProgressReportTicks = null;\n redetectBitrate(this);\n\n cancelReportPlaybackProgressPromise(this);\n const url = this.getUrl('Sessions/Playing/Stopped');\n\n return this.ajax({\n type: 'POST',\n data: JSON.stringify(options),\n contentType: 'application/json',\n url\n });\n }\n\n sendPlayCommand(sessionId, options) {\n if (!sessionId) {\n throw new Error('null sessionId');\n }\n\n if (!options) {\n throw new Error('null options');\n }\n\n const url = this.getUrl(`Sessions/${sessionId}/Playing`, options);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n sendCommand(sessionId, command) {\n if (!sessionId) {\n throw new Error('null sessionId');\n }\n\n if (!command) {\n throw new Error('null command');\n }\n\n const url = this.getUrl(`Sessions/${sessionId}/Command`);\n\n const ajaxOptions = {\n type: 'POST',\n url\n };\n\n ajaxOptions.data = JSON.stringify(command);\n ajaxOptions.contentType = 'application/json';\n\n return this.ajax(ajaxOptions);\n }\n\n sendMessageCommand(sessionId, options) {\n if (!sessionId) {\n throw new Error('null sessionId');\n }\n\n if (!options) {\n throw new Error('null options');\n }\n\n const url = this.getUrl(`Sessions/${sessionId}/Message`);\n\n const ajaxOptions = {\n type: 'POST',\n url\n };\n\n ajaxOptions.data = JSON.stringify(options);\n ajaxOptions.contentType = 'application/json';\n\n return this.ajax(ajaxOptions);\n }\n\n sendPlayStateCommand(sessionId, command, options) {\n if (!sessionId) {\n throw new Error('null sessionId');\n }\n\n if (!command) {\n throw new Error('null command');\n }\n\n const url = this.getUrl(`Sessions/${sessionId}/Playing/${command}`, options || {});\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n /**\n * Gets a list of all the active SyncPlay groups from the server.\n * @returns {Promise} A Promise that resolves to the list of active groups.\n * @since 10.6.0\n */\n getSyncPlayGroups() {\n const url = this.getUrl(`SyncPlay/List`);\n\n return this.ajax({\n type: 'GET',\n url: url\n });\n }\n\n /**\n * Creates a SyncPlay group on the server with the current client as member.\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n createSyncPlayGroup() {\n const url = this.getUrl(`SyncPlay/New`);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Joins the client to a given SyncPlay group on the server.\n * @param {object} options Information about the SyncPlay group to join.\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n joinSyncPlayGroup(options = {}) {\n const url = this.getUrl(`SyncPlay/Join`, options);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Leaves the current SyncPlay group.\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n leaveSyncPlayGroup() {\n const url = this.getUrl(`SyncPlay/Leave`);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Sends a ping to the SyncPlay group on the server.\n * @param {object} options Information about the ping\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n sendSyncPlayPing(options = {}) {\n const url = this.getUrl(`SyncPlay/Ping`, options);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Requests a playback start for the SyncPlay group\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n requestSyncPlayStart() {\n const url = this.getUrl(`SyncPlay/Play`);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Requests a playback pause for the SyncPlay group\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n requestSyncPlayPause() {\n const url = this.getUrl(`SyncPlay/Pause`);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n /**\n * Requests a playback seek for the SyncPlay group\n * @param {object} options Object containing the requested seek position.\n * @returns {Promise} A Promise fulfilled upon request completion.\n * @since 10.6.0\n */\n requestSyncPlaySeek(options = {}) {\n const url = this.getUrl(`SyncPlay/Seek`, options);\n\n return this.ajax({\n type: 'POST',\n url: url\n });\n }\n\n createPackageReview(review) {\n const url = this.getUrl(`Packages/Reviews/${review.id}`, review);\n\n return this.ajax({\n type: 'POST',\n url\n });\n }\n\n getPackageReviews(packageId, minRating, maxRating, limit) {\n if (!packageId) {\n throw new Error('null packageId');\n }\n\n const options = {};\n\n if (minRating) {\n options.MinRating = minRating;\n }\n if (maxRating) {\n options.MaxRating = maxRating;\n }\n if (limit) {\n options.Limit = limit;\n }\n\n const url = this.getUrl(`Packages/${packageId}/Reviews`, options);\n\n return this.getJSON(url);\n }\n\n getSavedEndpointInfo() {\n return this._endPointInfo;\n }\n\n getEndpointInfo() {\n const savedValue = this._endPointInfo;\n if (savedValue) {\n return Promise.resolve(savedValue);\n }\n\n const instance = this;\n return this.getJSON(this.getUrl('System/Endpoint')).then((endPointInfo) => {\n setSavedEndpointInfo(instance, endPointInfo);\n return endPointInfo;\n });\n }\n\n getLatestItems(options = {}) {\n return this.getJSON(this.getUrl(`Users/${this.getCurrentUserId()}/Items/Latest`, options));\n }\n\n getFilters(options) {\n return this.getJSON(this.getUrl('Items/Filters2', options));\n }\n\n setSystemInfo(info) {\n this._serverVersion = info.Version;\n }\n\n serverVersion() {\n return this._serverVersion;\n }\n\n isMinServerVersion(version) {\n const serverVersion = this.serverVersion();\n\n if (serverVersion) {\n return compareVersions(serverVersion, version) >= 0;\n }\n\n return false;\n }\n\n handleMessageReceived(msg) {\n onMessageReceivedInternal(this, msg);\n }\n}\n\nfunction setSavedEndpointInfo(instance, info) {\n instance._endPointInfo = info;\n}\n\nfunction getTryConnectPromise(instance, url, state, resolve, reject) {\n console.log('getTryConnectPromise ' + url);\n\n fetchWithTimeout(\n instance.getUrl('system/info/public', null, url),\n {\n method: 'GET',\n accept: 'application/json'\n\n // Commenting this out since the fetch api doesn't have a timeout option yet\n //timeout: timeout\n },\n 15000\n ).then(\n () => {\n if (!state.resolved) {\n state.resolved = true;\n\n console.log('Reconnect succeeded to ' + url);\n instance.serverAddress(url);\n resolve();\n }\n },\n () => {\n if (!state.resolved) {\n console.log('Reconnect failed to ' + url);\n\n state.rejects++;\n if (state.rejects >= state.numAddresses) {\n reject();\n }\n }\n }\n );\n}\n\nfunction tryReconnectInternal(instance) {\n const addresses = [];\n const addressesStrings = [];\n\n const serverInfo = instance.serverInfo();\n if (serverInfo.LocalAddress && addressesStrings.indexOf(serverInfo.LocalAddress) === -1) {\n addresses.push({ url: serverInfo.LocalAddress, timeout: 0 });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n if (serverInfo.ManualAddress && addressesStrings.indexOf(serverInfo.ManualAddress) === -1) {\n addresses.push({ url: serverInfo.ManualAddress, timeout: 100 });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n if (serverInfo.RemoteAddress && addressesStrings.indexOf(serverInfo.RemoteAddress) === -1) {\n addresses.push({ url: serverInfo.RemoteAddress, timeout: 200 });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n\n console.log('tryReconnect: ' + addressesStrings.join('|'));\n\n return new Promise((resolve, reject) => {\n const state = {};\n state.numAddresses = addresses.length;\n state.rejects = 0;\n\n addresses.map((url) => {\n setTimeout(() => {\n if (!state.resolved) {\n getTryConnectPromise(instance, url.url, state, resolve, reject);\n }\n }, url.timeout);\n });\n });\n}\n\nfunction tryReconnect(instance, retryCount) {\n retryCount = retryCount || 0;\n\n if (retryCount >= 20) {\n return Promise.reject();\n }\n\n return tryReconnectInternal(instance).catch((err) => {\n console.log('error in tryReconnectInternal: ' + (err || ''));\n\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n tryReconnect(instance, retryCount + 1).then(resolve, reject);\n }, 500);\n });\n });\n}\n\nfunction getCachedUser(instance, userId) {\n const serverId = instance.serverId();\n if (!serverId) {\n return null;\n }\n\n const json = appStorage.getItem(`user-${userId}-${serverId}`);\n\n if (json) {\n return JSON.parse(json);\n }\n\n return null;\n}\n\nfunction onWebSocketMessage(msg) {\n const instance = this;\n msg = JSON.parse(msg.data);\n onMessageReceivedInternal(instance, msg);\n}\n\nconst messageIdsReceived = {};\n\nfunction onMessageReceivedInternal(instance, msg) {\n const messageId = msg.MessageId;\n if (messageId) {\n // message was already received via another protocol\n if (messageIdsReceived[messageId]) {\n return;\n }\n\n messageIdsReceived[messageId] = true;\n }\n\n if (msg.MessageType === 'UserDeleted') {\n instance._currentUser = null;\n } else if (msg.MessageType === 'UserUpdated' || msg.MessageType === 'UserConfigurationUpdated') {\n const user = msg.Data;\n if (user.Id === instance.getCurrentUserId()) {\n instance._currentUser = null;\n }\n } else if (msg.MessageType === 'KeepAlive') {\n console.debug('Received KeepAlive from server.');\n } else if (msg.MessageType === 'ForceKeepAlive') {\n console.debug(`Received ForceKeepAlive from server. Timeout is ${msg.Data} seconds.`);\n instance.sendWebSocketMessage('KeepAlive');\n scheduleKeepAlive(instance, msg.Data);\n }\n\n events.trigger(instance, 'message', [msg]);\n}\n\n/**\n * Starts a poller that sends KeepAlive messages using a WebSocket connection.\n * @param {Object} instance The WebSocket connection.\n * @param {number} timeout The number of seconds after which the WebSocket is considered lost by the server.\n * @returns {number} The id of the interval.\n * @since 10.6.0\n */\nfunction scheduleKeepAlive(instance, timeout) {\n clearKeepAlive(instance);\n instance.keepAliveInterval = setInterval(() => {\n instance.sendWebSocketMessage('KeepAlive');\n }, timeout * 1000 * 0.5);\n return instance.keepAliveInterval;\n}\n\n/**\n * Stops the poller that is sending KeepAlive messages on a WebSocket connection.\n * @param {Object} instance The WebSocket connection.\n * @since 10.6.0\n */\nfunction clearKeepAlive(instance) {\n console.debug('Clearing KeepAlive for', instance);\n if (instance.keepAliveInterval) {\n clearInterval(instance.keepAliveInterval);\n instance.keepAliveInterval = null;\n }\n}\n\nfunction onWebSocketOpen() {\n const instance = this;\n console.log('web socket connection opened');\n events.trigger(instance, 'websocketopen');\n}\n\nfunction onWebSocketError() {\n const instance = this;\n clearKeepAlive(instance);\n events.trigger(instance, 'websocketerror');\n}\n\nfunction setSocketOnClose(apiClient, socket) {\n socket.onclose = () => {\n console.log('web socket closed');\n\n clearKeepAlive(socket);\n if (apiClient._webSocket === socket) {\n console.log('nulling out web socket');\n apiClient._webSocket = null;\n }\n\n setTimeout(() => {\n events.trigger(apiClient, 'websocketclose');\n }, 0);\n };\n}\n\nfunction normalizeReturnBitrate(instance, bitrate) {\n if (!bitrate) {\n if (instance.lastDetectedBitrate) {\n return instance.lastDetectedBitrate;\n }\n\n return Promise.reject();\n }\n\n let result = Math.round(bitrate * 0.7);\n\n // allow configuration of this\n if (instance.getMaxBandwidth) {\n const maxRate = instance.getMaxBandwidth();\n if (maxRate) {\n result = Math.min(result, maxRate);\n }\n }\n\n instance.lastDetectedBitrate = result;\n instance.lastDetectedBitrateTime = new Date().getTime();\n\n return result;\n}\n\nfunction detectBitrateInternal(instance, tests, index, currentBitrate) {\n if (index >= tests.length) {\n return normalizeReturnBitrate(instance, currentBitrate);\n }\n\n const test = tests[index];\n\n return instance.getDownloadSpeed(test.bytes).then(\n (bitrate) => {\n if (bitrate < test.threshold) {\n return normalizeReturnBitrate(instance, bitrate);\n } else {\n return detectBitrateInternal(instance, tests, index + 1, bitrate);\n }\n },\n () => normalizeReturnBitrate(instance, currentBitrate)\n );\n}\n\nfunction detectBitrateWithEndpointInfo(instance, endpointInfo) {\n if (endpointInfo.IsInNetwork) {\n const result = 140000000;\n instance.lastDetectedBitrate = result;\n instance.lastDetectedBitrateTime = new Date().getTime();\n return result;\n }\n\n return detectBitrateInternal(\n instance,\n [\n {\n bytes: 500000,\n threshold: 500000\n },\n {\n bytes: 1000000,\n threshold: 20000000\n },\n {\n bytes: 3000000,\n threshold: 50000000\n }\n ],\n 0\n );\n}\n\nfunction getRemoteImagePrefix(instance, options) {\n let urlPrefix;\n\n if (options.artist) {\n urlPrefix = `Artists/${instance.encodeName(options.artist)}`;\n delete options.artist;\n } else if (options.person) {\n urlPrefix = `Persons/${instance.encodeName(options.person)}`;\n delete options.person;\n } else if (options.genre) {\n urlPrefix = `Genres/${instance.encodeName(options.genre)}`;\n delete options.genre;\n } else if (options.musicGenre) {\n urlPrefix = `MusicGenres/${instance.encodeName(options.musicGenre)}`;\n delete options.musicGenre;\n } else if (options.studio) {\n urlPrefix = `Studios/${instance.encodeName(options.studio)}`;\n delete options.studio;\n } else {\n urlPrefix = `Items/${options.itemId}`;\n delete options.itemId;\n }\n\n return urlPrefix;\n}\n\nfunction normalizeImageOptions(instance, options) {\n let ratio = window.devicePixelRatio || 1;\n\n if (ratio) {\n if (options.minScale) {\n ratio = Math.max(options.minScale, ratio);\n }\n\n if (options.width) {\n options.width = Math.round(options.width * ratio);\n }\n if (options.height) {\n options.height = Math.round(options.height * ratio);\n }\n if (options.maxWidth) {\n options.maxWidth = Math.round(options.maxWidth * ratio);\n }\n if (options.maxHeight) {\n options.maxHeight = Math.round(options.maxHeight * ratio);\n }\n }\n\n options.quality = options.quality || instance.getDefaultImageQuality(options.type);\n\n if (instance.normalizeImageOptions) {\n instance.normalizeImageOptions(options);\n }\n}\n\nfunction compareVersions(a, b) {\n // -1 a is smaller\n // 1 a is larger\n // 0 equal\n a = a.split('.');\n b = b.split('.');\n\n for (let i = 0, length = Math.max(a.length, b.length); i < length; i++) {\n const aVal = parseInt(a[i] || '0');\n const bVal = parseInt(b[i] || '0');\n\n if (aVal < bVal) {\n return -1;\n }\n\n if (aVal > bVal) {\n return 1;\n }\n }\n\n return 0;\n}\n\nexport default ApiClient;\n","import ApiClient from './apiClient';\n\nconst localPrefix = 'local:';\nconst localViewPrefix = 'localview:';\n\nfunction isLocalId(str) {\n return startsWith(str, localPrefix);\n}\n\nfunction isLocalViewId(str) {\n return startsWith(str, localViewPrefix);\n}\n\nfunction isTopLevelLocalViewId(str) {\n return str === 'localview';\n}\n\nfunction stripLocalPrefix(str) {\n let res = stripStart(str, localPrefix);\n res = stripStart(res, localViewPrefix);\n\n return res;\n}\n\nfunction startsWith(str, find) {\n if (str && find && str.length > find.length) {\n if (str.indexOf(find) === 0) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction stripStart(str, find) {\n if (startsWith(str, find)) {\n return str.substr(find.length);\n }\n\n return str;\n}\n\nfunction createEmptyList() {\n const result = {\n Items: [],\n TotalRecordCount: 0\n };\n\n return result;\n}\n\nfunction convertGuidToLocal(guid) {\n if (!guid) {\n return null;\n }\n\n if (isLocalId(guid)) {\n return guid;\n }\n\n return `local:${guid}`;\n}\n\nfunction adjustGuidProperties(downloadedItem) {\n downloadedItem.Id = convertGuidToLocal(downloadedItem.Id);\n downloadedItem.SeriesId = convertGuidToLocal(downloadedItem.SeriesId);\n downloadedItem.SeasonId = convertGuidToLocal(downloadedItem.SeasonId);\n\n downloadedItem.AlbumId = convertGuidToLocal(downloadedItem.AlbumId);\n downloadedItem.ParentId = convertGuidToLocal(downloadedItem.ParentId);\n downloadedItem.ParentThumbItemId = convertGuidToLocal(downloadedItem.ParentThumbItemId);\n downloadedItem.ParentPrimaryImageItemId = convertGuidToLocal(downloadedItem.ParentPrimaryImageItemId);\n downloadedItem.PrimaryImageItemId = convertGuidToLocal(downloadedItem.PrimaryImageItemId);\n downloadedItem.ParentLogoItemId = convertGuidToLocal(downloadedItem.ParentLogoItemId);\n downloadedItem.ParentBackdropItemId = convertGuidToLocal(downloadedItem.ParentBackdropItemId);\n\n downloadedItem.ParentBackdropImageTags = null;\n}\n\nfunction getLocalView(instance, serverId, userId) {\n return instance.getLocalFolders(serverId, userId).then((views) => {\n let localView = null;\n\n if (views.length > 0) {\n localView = {\n Name: instance.downloadsTitleText || 'Downloads',\n ServerId: serverId,\n Id: 'localview',\n Type: 'localview',\n IsFolder: true\n };\n }\n\n return Promise.resolve(localView);\n });\n}\n\n/**\n * Creates a new api client instance\n * @param {String} serverAddress\n * @param {String} clientName s\n * @param {String} applicationVersion\n */\nclass ApiClientCore extends ApiClient {\n constructor(\n serverAddress,\n clientName,\n applicationVersion,\n deviceName,\n deviceId,\n devicePixelRatio,\n localAssetManager\n ) {\n super(serverAddress, clientName, applicationVersion, deviceName, deviceId, devicePixelRatio);\n this.localAssetManager = localAssetManager;\n }\n\n getPlaybackInfo(itemId, options, deviceProfile) {\n const onFailure = () => ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile);\n\n if (isLocalId(itemId)) {\n return this.localAssetManager.getLocalItem(this.serverId(), stripLocalPrefix(itemId)).then((item) => {\n // TODO: This was already done during the sync process, right? If so, remove it\n const mediaSources = item.Item.MediaSources.map((m) => {\n m.SupportsDirectPlay = true;\n m.SupportsDirectStream = false;\n m.SupportsTranscoding = false;\n m.IsLocal = true;\n return m;\n });\n\n return {\n MediaSources: mediaSources\n };\n }, onFailure);\n }\n\n var instance = this;\n return this.localAssetManager.getLocalItem(this.serverId(), itemId).then((item) => {\n if (item) {\n const mediaSources = item.Item.MediaSources.map((m) => {\n m.SupportsDirectPlay = true;\n m.SupportsDirectStream = false;\n m.SupportsTranscoding = false;\n m.IsLocal = true;\n return m;\n });\n\n return instance.localAssetManager.fileExists(item.LocalPath).then((exists) => {\n if (exists) {\n const res = {\n MediaSources: mediaSources\n };\n\n return Promise.resolve(res);\n }\n\n return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile);\n }, onFailure);\n }\n\n return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile);\n }, onFailure);\n }\n\n getItems(userId, options) {\n const serverInfo = this.serverInfo();\n let i;\n\n if (serverInfo && options.ParentId === 'localview') {\n return this.getLocalFolders(serverInfo.Id, userId).then((items) => {\n const result = {\n Items: items,\n TotalRecordCount: items.length\n };\n\n return Promise.resolve(result);\n });\n } else if (\n serverInfo &&\n options &&\n (isLocalId(options.ParentId) ||\n isLocalId(options.SeriesId) ||\n isLocalId(options.SeasonId) ||\n isLocalViewId(options.ParentId) ||\n isLocalId(options.AlbumIds))\n ) {\n return this.localAssetManager.getViewItems(serverInfo.Id, userId, options).then((items) => {\n items.forEach((item) => {\n adjustGuidProperties(item);\n });\n\n const result = {\n Items: items,\n TotalRecordCount: items.length\n };\n\n return Promise.resolve(result);\n });\n } else if (options && options.ExcludeItemIds && options.ExcludeItemIds.length) {\n const exItems = options.ExcludeItemIds.split(',');\n\n for (i = 0; i < exItems.length; i++) {\n if (isLocalId(exItems[i])) {\n return Promise.resolve(createEmptyList());\n }\n }\n } else if (options && options.Ids && options.Ids.length) {\n const ids = options.Ids.split(',');\n let hasLocal = false;\n\n for (i = 0; i < ids.length; i++) {\n if (isLocalId(ids[i])) {\n hasLocal = true;\n }\n }\n\n if (hasLocal) {\n return this.localAssetManager.getItemsFromIds(serverInfo.Id, ids).then((items) => {\n items.forEach((item) => {\n adjustGuidProperties(item);\n });\n\n const result = {\n Items: items,\n TotalRecordCount: items.length\n };\n\n return Promise.resolve(result);\n });\n }\n }\n\n return ApiClient.prototype.getItems.call(this, userId, options);\n }\n\n getUserViews(options, userId) {\n const instance = this;\n\n options = options || {};\n\n const basePromise = ApiClient.prototype.getUserViews.call(instance, options, userId);\n\n if (!options.enableLocalView) {\n return basePromise;\n }\n\n return basePromise.then((result) => {\n const serverInfo = instance.serverInfo();\n if (serverInfo) {\n return getLocalView(instance, serverInfo.Id, userId).then((localView) => {\n if (localView) {\n result.Items.push(localView);\n result.TotalRecordCount++;\n }\n\n return Promise.resolve(result);\n });\n }\n\n return Promise.resolve(result);\n });\n }\n\n getItem(userId, itemId) {\n if (!itemId) {\n throw new Error('null itemId');\n }\n\n if (itemId) {\n itemId = itemId.toString();\n }\n\n let serverInfo;\n\n if (isTopLevelLocalViewId(itemId)) {\n serverInfo = this.serverInfo();\n\n if (serverInfo) {\n return getLocalView(this, serverInfo.Id, userId);\n }\n }\n\n if (isLocalViewId(itemId)) {\n serverInfo = this.serverInfo();\n\n if (serverInfo) {\n return this.getLocalFolders(serverInfo.Id, userId).then((items) => {\n const views = items.filter((item) => item.Id === itemId);\n\n if (views.length > 0) {\n return Promise.resolve(views[0]);\n }\n\n // TODO: Test consequence of this\n return Promise.reject();\n });\n }\n }\n\n if (isLocalId(itemId)) {\n serverInfo = this.serverInfo();\n\n if (serverInfo) {\n return this.localAssetManager.getLocalItem(serverInfo.Id, stripLocalPrefix(itemId)).then((item) => {\n adjustGuidProperties(item.Item);\n\n return Promise.resolve(item.Item);\n });\n }\n }\n\n return ApiClient.prototype.getItem.call(this, userId, itemId);\n }\n\n getLocalFolders(userId) {\n const serverInfo = this.serverInfo();\n userId = userId || serverInfo.UserId;\n\n return this.localAssetManager.getViews(serverInfo.Id, userId);\n }\n\n getNextUpEpisodes(options) {\n if (options.SeriesId) {\n if (isLocalId(options.SeriesId)) {\n return Promise.resolve(createEmptyList());\n }\n }\n\n return ApiClient.prototype.getNextUpEpisodes.call(this, options);\n }\n\n getSeasons(itemId, options) {\n if (isLocalId(itemId)) {\n options.SeriesId = itemId;\n options.IncludeItemTypes = 'Season';\n return this.getItems(this.getCurrentUserId(), options);\n }\n\n return ApiClient.prototype.getSeasons.call(this, itemId, options);\n }\n\n getEpisodes(itemId, options) {\n if (isLocalId(options.SeasonId) || isLocalId(options.seasonId)) {\n options.SeriesId = itemId;\n options.IncludeItemTypes = 'Episode';\n return this.getItems(this.getCurrentUserId(), options);\n }\n\n // get episodes by recursion\n if (isLocalId(itemId)) {\n options.SeriesId = itemId;\n options.IncludeItemTypes = 'Episode';\n return this.getItems(this.getCurrentUserId(), options);\n }\n\n return ApiClient.prototype.getEpisodes.call(this, itemId, options);\n }\n\n getLatestOfflineItems(options) {\n // Supported options\n // MediaType - Audio/Video/Photo/Book/Game\n // Limit\n // Filters: 'IsNotFolder' or 'IsFolder'\n\n options.SortBy = 'DateCreated';\n options.SortOrder = 'Descending';\n\n const serverInfo = this.serverInfo();\n\n if (serverInfo) {\n return this.localAssetManager.getViewItems(serverInfo.Id, null, options).then((items) => {\n items.forEach((item) => {\n adjustGuidProperties(item);\n });\n\n return Promise.resolve(items);\n });\n }\n\n return Promise.resolve([]);\n }\n\n getThemeMedia(userId, itemId, inherit) {\n if (isLocalViewId(itemId) || isLocalId(itemId) || isTopLevelLocalViewId(itemId)) {\n return Promise.reject();\n }\n\n return ApiClient.prototype.getThemeMedia.call(this, userId, itemId, inherit);\n }\n\n getSpecialFeatures(userId, itemId) {\n if (isLocalId(itemId)) {\n return Promise.resolve([]);\n }\n\n return ApiClient.prototype.getSpecialFeatures.call(this, userId, itemId);\n }\n\n getSimilarItems(itemId, options) {\n if (isLocalId(itemId)) {\n return Promise.resolve(createEmptyList());\n }\n\n return ApiClient.prototype.getSimilarItems.call(this, itemId, options);\n }\n\n updateFavoriteStatus(userId, itemId, isFavorite) {\n if (isLocalId(itemId)) {\n return Promise.resolve();\n }\n\n return ApiClient.prototype.updateFavoriteStatus.call(this, userId, itemId, isFavorite);\n }\n\n getScaledImageUrl(itemId, options) {\n if (isLocalId(itemId) || (options && options.itemid && isLocalId(options.itemid))) {\n const serverInfo = this.serverInfo();\n const id = stripLocalPrefix(itemId);\n\n return this.localAssetManager.getImageUrl(serverInfo.Id, id, options);\n }\n\n return ApiClient.prototype.getScaledImageUrl.call(this, itemId, options);\n }\n\n reportPlaybackStart(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n if (isLocalId(options.ItemId)) {\n return Promise.resolve();\n }\n\n return ApiClient.prototype.reportPlaybackStart.call(this, options);\n }\n\n reportPlaybackProgress(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n if (isLocalId(options.ItemId)) {\n const serverInfo = this.serverInfo();\n\n if (serverInfo) {\n const instance = this;\n return this.localAssetManager\n .getLocalItem(serverInfo.Id, stripLocalPrefix(options.ItemId))\n .then((item) => {\n const libraryItem = item.Item;\n\n if (libraryItem.MediaType === 'Video' || libraryItem.Type === 'AudioBook') {\n libraryItem.UserData = libraryItem.UserData || {};\n libraryItem.UserData.PlaybackPositionTicks = options.PositionTicks;\n libraryItem.UserData.PlayedPercentage = Math.min(\n libraryItem.RunTimeTicks\n ? 100 * ((options.PositionTicks || 0) / libraryItem.RunTimeTicks)\n : 0,\n 100\n );\n return instance.localAssetManager.addOrUpdateLocalItem(item);\n }\n\n return Promise.resolve();\n });\n }\n\n return Promise.resolve();\n }\n\n return ApiClient.prototype.reportPlaybackProgress.call(this, options);\n }\n\n reportPlaybackStopped(options) {\n if (!options) {\n throw new Error('null options');\n }\n\n if (isLocalId(options.ItemId)) {\n const serverInfo = this.serverInfo();\n\n const action = {\n Date: new Date().getTime(),\n ItemId: stripLocalPrefix(options.ItemId),\n PositionTicks: options.PositionTicks,\n ServerId: serverInfo.Id,\n Type: 0, // UserActionType.PlayedItem\n UserId: this.getCurrentUserId()\n };\n\n return this.localAssetManager.recordUserAction(action);\n }\n\n return ApiClient.prototype.reportPlaybackStopped.call(this, options);\n }\n\n getIntros(itemId) {\n if (isLocalId(itemId)) {\n return Promise.resolve({\n Items: [],\n TotalRecordCount: 0\n });\n }\n\n return ApiClient.prototype.getIntros.call(this, itemId);\n }\n\n getInstantMixFromItem(itemId, options) {\n if (isLocalId(itemId)) {\n return Promise.resolve({\n Items: [],\n TotalRecordCount: 0\n });\n }\n\n return ApiClient.prototype.getInstantMixFromItem.call(this, itemId, options);\n }\n\n getItemDownloadUrl(itemId) {\n if (isLocalId(itemId)) {\n const serverInfo = this.serverInfo();\n\n if (serverInfo) {\n return this.localAssetManager\n .getLocalItem(serverInfo.Id, stripLocalPrefix(itemId))\n .then((item) => Promise.resolve(item.LocalPath));\n }\n }\n\n return ApiClient.prototype.getItemDownloadUrl.call(this, itemId);\n }\n}\n\nexport default ApiClientCore;\n","import events from './events';\nimport ApiClient from './apiClient';\n\nconst defaultTimeout = 20000;\n\nconst ConnectionMode = {\n Local: 0,\n Remote: 1,\n Manual: 2\n};\n\nfunction getServerAddress(server, mode) {\n switch (mode) {\n case ConnectionMode.Local:\n return server.LocalAddress;\n case ConnectionMode.Manual:\n return server.ManualAddress;\n case ConnectionMode.Remote:\n return server.RemoteAddress;\n default:\n return server.ManualAddress || server.LocalAddress || server.RemoteAddress;\n }\n}\n\nfunction paramsToString(params) {\n const values = [];\n\n for (const key in params) {\n const value = params[key];\n\n if (value !== null && value !== undefined && value !== '') {\n values.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n }\n }\n return values.join('&');\n}\n\nfunction resolveFailure(instance, resolve) {\n resolve({\n State: 'Unavailable'\n });\n}\n\nfunction mergeServers(credentialProvider, list1, list2) {\n for (let i = 0, length = list2.length; i < length; i++) {\n credentialProvider.addOrUpdateServer(list1, list2[i]);\n }\n\n return list1;\n}\n\nfunction updateServerInfo(server, systemInfo) {\n server.Name = systemInfo.ServerName;\n\n if (systemInfo.Id) {\n server.Id = systemInfo.Id;\n }\n if (systemInfo.LocalAddress) {\n server.LocalAddress = systemInfo.LocalAddress;\n }\n}\n\nfunction getEmbyServerUrl(baseUrl, handler) {\n return `${baseUrl}/${handler}`;\n}\n\nfunction getFetchPromise(request) {\n const headers = request.headers || {};\n\n if (request.dataType === 'json') {\n headers.accept = 'application/json';\n }\n\n const fetchRequest = {\n headers,\n method: request.type,\n credentials: 'same-origin'\n };\n\n let contentType = request.contentType;\n\n if (request.data) {\n if (typeof request.data === 'string') {\n fetchRequest.body = request.data;\n } else {\n fetchRequest.body = paramsToString(request.data);\n\n contentType = contentType || 'application/x-www-form-urlencoded; charset=UTF-8';\n }\n }\n\n if (contentType) {\n headers['Content-Type'] = contentType;\n }\n\n if (!request.timeout) {\n return fetch(request.url, fetchRequest);\n }\n\n return fetchWithTimeout(request.url, fetchRequest, request.timeout);\n}\n\nfunction fetchWithTimeout(url, options, timeoutMs) {\n console.log(`fetchWithTimeout: timeoutMs: ${timeoutMs}, url: ${url}`);\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(reject, timeoutMs);\n\n options = options || {};\n options.credentials = 'same-origin';\n\n fetch(url, options).then(\n (response) => {\n clearTimeout(timeout);\n\n console.log(`fetchWithTimeout: succeeded connecting to url: ${url}`);\n\n resolve(response);\n },\n (error) => {\n clearTimeout(timeout);\n\n console.log(`fetchWithTimeout: timed out connecting to url: ${url}`);\n\n reject();\n }\n );\n });\n}\n\nfunction ajax(request) {\n if (!request) {\n throw new Error('Request cannot be null');\n }\n\n request.headers = request.headers || {};\n\n console.log(`ConnectionManager requesting url: ${request.url}`);\n\n return getFetchPromise(request).then(\n (response) => {\n console.log(`ConnectionManager response status: ${response.status}, url: ${request.url}`);\n\n if (response.status < 400) {\n if (request.dataType === 'json' || request.headers.accept === 'application/json') {\n return response.json();\n } else {\n return response;\n }\n } else {\n return Promise.reject(response);\n }\n },\n (err) => {\n console.log(`ConnectionManager request failed to url: ${request.url}`);\n throw err;\n }\n );\n}\n\nfunction replaceAll(originalString, strReplace, strWith) {\n const reg = new RegExp(strReplace, 'ig');\n return originalString.replace(reg, strWith);\n}\n\nfunction normalizeAddress(address) {\n // Attempt to correct bad input\n address = address.trim();\n\n // Seeing failures in iOS when protocol isn't lowercase\n address = replaceAll(address, 'Http:', 'http:');\n address = replaceAll(address, 'Https:', 'https:');\n\n return address;\n}\n\nfunction stringEqualsIgnoreCase(str1, str2) {\n return (str1 || '').toLowerCase() === (str2 || '').toLowerCase();\n}\n\nfunction compareVersions(a, b) {\n // -1 a is smaller\n // 1 a is larger\n // 0 equal\n a = a.split('.');\n b = b.split('.');\n\n for (let i = 0, length = Math.max(a.length, b.length); i < length; i++) {\n const aVal = parseInt(a[i] || '0');\n const bVal = parseInt(b[i] || '0');\n\n if (aVal < bVal) {\n return -1;\n }\n\n if (aVal > bVal) {\n return 1;\n }\n }\n\n return 0;\n}\n\nexport default class ConnectionManager {\n constructor(credentialProvider, appName, appVersion, deviceName, deviceId, capabilities) {\n console.log('Begin ConnectionManager constructor');\n\n const self = this;\n this._apiClients = [];\n\n self._minServerVersion = '3.2.33';\n\n self.appVersion = () => appVersion;\n\n self.appName = () => appName;\n\n self.capabilities = () => capabilities;\n\n self.deviceId = () => deviceId;\n\n self.credentialProvider = () => credentialProvider;\n\n self.getServerInfo = (id) => {\n const servers = credentialProvider.credentials().Servers;\n\n return servers.filter((s) => s.Id === id)[0];\n };\n\n self.getLastUsedServer = () => {\n const servers = credentialProvider.credentials().Servers;\n\n servers.sort((a, b) => (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0));\n\n if (!servers.length) {\n return null;\n }\n\n return servers[0];\n };\n\n self.addApiClient = (apiClient) => {\n self._apiClients.push(apiClient);\n\n const existingServers = credentialProvider\n .credentials()\n .Servers.filter(\n (s) =>\n stringEqualsIgnoreCase(s.ManualAddress, apiClient.serverAddress()) ||\n stringEqualsIgnoreCase(s.LocalAddress, apiClient.serverAddress()) ||\n stringEqualsIgnoreCase(s.RemoteAddress, apiClient.serverAddress())\n );\n\n const existingServer = existingServers.length ? existingServers[0] : apiClient.serverInfo();\n existingServer.DateLastAccessed = new Date().getTime();\n existingServer.LastConnectionMode = ConnectionMode.Manual;\n existingServer.ManualAddress = apiClient.serverAddress();\n\n if (apiClient.manualAddressOnly) {\n existingServer.manualAddressOnly = true;\n }\n\n apiClient.serverInfo(existingServer);\n\n apiClient.onAuthenticated = (instance, result) => onAuthenticated(instance, result, {}, true);\n\n if (!existingServers.length) {\n const credentials = credentialProvider.credentials();\n credentials.Servers = [existingServer];\n credentialProvider.credentials(credentials);\n }\n\n events.trigger(self, 'apiclientcreated', [apiClient]);\n };\n\n self.clearData = () => {\n console.log('connection manager clearing data');\n\n const credentials = credentialProvider.credentials();\n credentials.Servers = [];\n credentialProvider.credentials(credentials);\n };\n\n self._getOrAddApiClient = (server, serverUrl) => {\n let apiClient = self.getApiClient(server.Id);\n\n if (!apiClient) {\n apiClient = new ApiClient(serverUrl, appName, appVersion, deviceName, deviceId);\n\n self._apiClients.push(apiClient);\n\n apiClient.serverInfo(server);\n\n apiClient.onAuthenticated = (instance, result) => {\n return onAuthenticated(instance, result, {}, true);\n };\n\n events.trigger(self, 'apiclientcreated', [apiClient]);\n }\n\n console.log('returning instance from getOrAddApiClient');\n return apiClient;\n };\n\n self.getOrCreateApiClient = (serverId) => {\n const credentials = credentialProvider.credentials();\n const servers = credentials.Servers.filter((s) => stringEqualsIgnoreCase(s.Id, serverId));\n\n if (!servers.length) {\n throw new Error(`Server not found: ${serverId}`);\n }\n\n const server = servers[0];\n\n return self._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode));\n };\n\n function onAuthenticated(apiClient, result, options, saveCredentials) {\n const credentials = credentialProvider.credentials();\n const servers = credentials.Servers.filter((s) => s.Id === result.ServerId);\n\n const server = servers.length ? servers[0] : apiClient.serverInfo();\n\n if (options.updateDateLastAccessed !== false) {\n server.DateLastAccessed = new Date().getTime();\n }\n server.Id = result.ServerId;\n\n if (saveCredentials) {\n server.UserId = result.User.Id;\n server.AccessToken = result.AccessToken;\n } else {\n server.UserId = null;\n server.AccessToken = null;\n }\n\n credentialProvider.addOrUpdateServer(credentials.Servers, server);\n credentialProvider.credentials(credentials);\n\n // set this now before updating server info, otherwise it won't be set in time\n apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;\n\n apiClient.serverInfo(server);\n afterConnected(apiClient, options);\n\n return onLocalUserSignIn(server, apiClient.serverAddress(), result.User);\n }\n\n function afterConnected(apiClient, options = {}) {\n if (options.reportCapabilities !== false) {\n apiClient.reportCapabilities(capabilities);\n }\n apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;\n\n if (options.enableWebSocket !== false) {\n console.log('calling apiClient.ensureWebSocket');\n\n apiClient.ensureWebSocket();\n }\n }\n\n function onLocalUserSignIn(server, serverUrl, user) {\n // Ensure this is created so that listeners of the event can get the apiClient instance\n self._getOrAddApiClient(server, serverUrl);\n\n // This allows the app to have a single hook that fires before any other\n const promise = self.onLocalUserSignedIn ? self.onLocalUserSignedIn.call(self, user) : Promise.resolve();\n\n return promise.then(() => {\n events.trigger(self, 'localusersignedin', [user]);\n });\n }\n\n function validateAuthentication(server, serverUrl) {\n return ajax({\n type: 'GET',\n url: getEmbyServerUrl(serverUrl, 'System/Info'),\n dataType: 'json',\n headers: {\n 'X-MediaBrowser-Token': server.AccessToken\n }\n }).then(\n (systemInfo) => {\n updateServerInfo(server, systemInfo);\n return Promise.resolve();\n },\n () => {\n server.UserId = null;\n server.AccessToken = null;\n return Promise.resolve();\n }\n );\n }\n\n function getImageUrl(localUser) {\n if (localUser && localUser.PrimaryImageTag) {\n const apiClient = self.getApiClient(localUser);\n\n const url = apiClient.getUserImageUrl(localUser.Id, {\n tag: localUser.PrimaryImageTag,\n type: 'Primary'\n });\n\n return {\n url,\n supportsParams: true\n };\n }\n\n return {\n url: null,\n supportsParams: false\n };\n }\n\n self.user = (apiClient) =>\n new Promise((resolve, reject) => {\n let localUser;\n\n function onLocalUserDone(e) {\n if (apiClient && apiClient.getCurrentUserId()) {\n apiClient.getCurrentUser().then((u) => {\n localUser = u;\n const image = getImageUrl(localUser);\n\n resolve({\n localUser,\n name: localUser ? localUser.Name : null,\n imageUrl: image.url,\n supportsImageParams: image.supportsParams\n });\n });\n }\n }\n\n if (apiClient && apiClient.getCurrentUserId()) {\n onLocalUserDone();\n }\n });\n\n self.logout = () => {\n const promises = [];\n\n for (let i = 0, length = self._apiClients.length; i < length; i++) {\n const apiClient = self._apiClients[i];\n\n if (apiClient.accessToken()) {\n promises.push(logoutOfServer(apiClient));\n }\n }\n\n return Promise.all(promises).then(() => {\n const credentials = credentialProvider.credentials();\n\n const servers = credentials.Servers.filter((u) => u.UserLinkType !== 'Guest');\n\n for (let j = 0, numServers = servers.length; j < numServers; j++) {\n const server = servers[j];\n\n server.UserId = null;\n server.AccessToken = null;\n server.ExchangeToken = null;\n }\n });\n };\n\n function logoutOfServer(apiClient) {\n const serverInfo = apiClient.serverInfo() || {};\n\n const logoutInfo = {\n serverId: serverInfo.Id\n };\n\n return apiClient.logout().then(\n () => {\n events.trigger(self, 'localusersignedout', [logoutInfo]);\n },\n () => {\n events.trigger(self, 'localusersignedout', [logoutInfo]);\n }\n );\n }\n\n self.getSavedServers = () => {\n const credentials = credentialProvider.credentials();\n\n const servers = credentials.Servers.slice(0);\n\n servers.sort((a, b) => (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0));\n\n return servers;\n };\n\n self.getAvailableServers = () => {\n console.log('Begin getAvailableServers');\n\n // Clone the array\n const credentials = credentialProvider.credentials();\n\n return Promise.all([findServers()]).then((responses) => {\n const foundServers = responses[0];\n let servers = credentials.Servers.slice(0);\n mergeServers(credentialProvider, servers, foundServers);\n\n servers.sort((a, b) => (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0));\n credentials.Servers = servers;\n credentialProvider.credentials(credentials);\n\n return servers;\n });\n };\n\n function findServers() {\n return new Promise((resolve, reject) => {\n var onFinish = function (foundServers) {\n var servers = foundServers.map((foundServer) => {\n var info = {\n Id: foundServer.Id,\n LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address,\n Name: foundServer.Name\n };\n info.LastConnectionMode = info.ManualAddress ? ConnectionMode.Manual : ConnectionMode.Local;\n return info;\n });\n resolve(servers);\n };\n\n if (window.NativeShell && typeof window.NativeShell.findServers === 'function') {\n window.NativeShell.findServers(1e3).then(onFinish, function () {\n onFinish([]);\n });\n } else {\n resolve([]);\n }\n });\n }\n\n function convertEndpointAddressToManualAddress(info) {\n if (info.Address && info.EndpointAddress) {\n let address = info.EndpointAddress.split(':')[0];\n\n // Determine the port, if any\n const parts = info.Address.split(':');\n if (parts.length > 1) {\n const portString = parts[parts.length - 1];\n\n if (!isNaN(parseInt(portString))) {\n address += `:${portString}`;\n }\n }\n\n return normalizeAddress(address);\n }\n\n return null;\n }\n\n self.connectToServers = (servers, options) => {\n console.log(`Begin connectToServers, with ${servers.length} servers`);\n\n const firstServer = servers.length ? servers[0] : null;\n // See if we have any saved credentials and can auto sign in\n if (firstServer) {\n return self.connectToServer(firstServer, options).then((result) => {\n if (result.State === 'Unavailable') {\n result.State = 'ServerSelection';\n }\n\n console.log('resolving connectToServers with result.State: ' + result.State);\n return result;\n });\n }\n\n return Promise.resolve({\n Servers: servers,\n State: 'ServerSelection'\n });\n };\n\n function getTryConnectPromise(url, connectionMode, state, resolve, reject) {\n console.log('getTryConnectPromise ' + url);\n\n ajax({\n url: getEmbyServerUrl(url, 'system/info/public'),\n timeout: defaultTimeout,\n type: 'GET',\n dataType: 'json'\n }).then(\n (result) => {\n if (!state.resolved) {\n state.resolved = true;\n\n console.log('Reconnect succeeded to ' + url);\n resolve({\n url: url,\n connectionMode: connectionMode,\n data: result\n });\n }\n },\n () => {\n console.log('Reconnect failed to ' + url);\n\n if (!state.resolved) {\n state.rejects++;\n if (state.rejects >= state.numAddresses) {\n reject();\n }\n }\n }\n );\n }\n\n function tryReconnect(serverInfo) {\n const addresses = [];\n const addressesStrings = [];\n\n // the timeouts are a small hack to try and ensure the remote address doesn't resolve first\n\n // manualAddressOnly is used for the local web app that always connects to a fixed address\n if (\n !serverInfo.manualAddressOnly &&\n serverInfo.LocalAddress &&\n addressesStrings.indexOf(serverInfo.LocalAddress) === -1\n ) {\n addresses.push({\n url: serverInfo.LocalAddress,\n mode: ConnectionMode.Local,\n timeout: 0\n });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n if (serverInfo.ManualAddress && addressesStrings.indexOf(serverInfo.ManualAddress) === -1) {\n addresses.push({\n url: serverInfo.ManualAddress,\n mode: ConnectionMode.Manual,\n timeout: 100\n });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n if (\n !serverInfo.manualAddressOnly &&\n serverInfo.RemoteAddress &&\n addressesStrings.indexOf(serverInfo.RemoteAddress) === -1\n ) {\n addresses.push({\n url: serverInfo.RemoteAddress,\n mode: ConnectionMode.Remote,\n timeout: 200\n });\n addressesStrings.push(addresses[addresses.length - 1].url);\n }\n\n console.log('tryReconnect: ' + addressesStrings.join('|'));\n\n return new Promise((resolve, reject) => {\n const state = {};\n state.numAddresses = addresses.length;\n state.rejects = 0;\n\n addresses.map((url) => {\n setTimeout(() => {\n if (!state.resolved) {\n getTryConnectPromise(url.url, url.mode, state, resolve, reject);\n }\n }, url.timeout);\n });\n });\n }\n\n self.connectToServer = (server, options) => {\n console.log('begin connectToServer');\n\n return new Promise((resolve, reject) => {\n options = options || {};\n\n tryReconnect(server).then(\n (result) => {\n const serverUrl = result.url;\n const connectionMode = result.connectionMode;\n result = result.data;\n\n if (compareVersions(self.minServerVersion(), result.Version) === 1) {\n console.log('minServerVersion requirement not met. Server version: ' + result.Version);\n resolve({\n State: 'ServerUpdateNeeded',\n Servers: [server]\n });\n } else if (server.Id && result.Id !== server.Id) {\n console.log(\n 'http request succeeded, but found a different server Id than what was expected'\n );\n resolveFailure(self, resolve);\n } else {\n onSuccessfulConnection(server, result, connectionMode, serverUrl, true, resolve, options);\n }\n },\n () => {\n resolveFailure(self, resolve);\n }\n );\n });\n };\n\n function onSuccessfulConnection(server, systemInfo, connectionMode, serverUrl, verifyLocalAuthentication, resolve, options={}) {\n const credentials = credentialProvider.credentials();\n\n if (options.enableAutoLogin === false) {\n server.UserId = null;\n server.AccessToken = null;\n } else if (server.AccessToken && verifyLocalAuthentication) {\n return void validateAuthentication(server, serverUrl).then(function () {\n onSuccessfulConnection(server, systemInfo, connectionMode, serverUrl, false, resolve, options);\n });\n }\n\n updateServerInfo(server, systemInfo);\n\n server.LastConnectionMode = connectionMode;\n\n if (options.updateDateLastAccessed !== false) {\n server.DateLastAccessed = new Date().getTime();\n }\n credentialProvider.addOrUpdateServer(credentials.Servers, server);\n credentialProvider.credentials(credentials);\n\n const result = {\n Servers: []\n };\n\n result.ApiClient = self._getOrAddApiClient(server, serverUrl);\n\n result.ApiClient.setSystemInfo(systemInfo);\n\n result.State = server.AccessToken && options.enableAutoLogin !== false ? 'SignedIn' : 'ServerSignIn';\n\n result.Servers.push(server);\n\n // set this now before updating server info, otherwise it won't be set in time\n result.ApiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;\n\n result.ApiClient.updateServerInfo(server, serverUrl);\n\n const resolveActions = function () {\n resolve(result);\n\n events.trigger(self, 'connected', [result]);\n };\n\n if (result.State === 'SignedIn') {\n afterConnected(result.ApiClient, options);\n\n result.ApiClient.getCurrentUser().then((user) => {\n onLocalUserSignIn(server, serverUrl, user).then(resolveActions, resolveActions);\n }, resolveActions);\n } else {\n resolveActions();\n }\n }\n\n function tryConnectToAddress(address, options) {\n const server = {\n ManualAddress: address,\n LastConnectionMode: ConnectionMode.Manual\n };\n\n return self.connectToServer(server, options).then((result) => {\n // connectToServer never rejects, but resolves with State='Unavailable'\n if (result.State === 'Unavailable') {\n return Promise.reject();\n }\n return result;\n });\n }\n\n self.connectToAddress = function (address, options) {\n if (!address) {\n return Promise.reject();\n }\n\n address = normalizeAddress(address);\n\n let urls = [];\n\n if (/^[^:]+:\\/\\//.test(address)) {\n // Protocol specified - connect as is\n urls.push(address);\n } else {\n urls.push(`https://${address}`);\n urls.push(`http://${address}`);\n }\n\n let i = 0;\n\n function onFail() {\n console.log(`connectToAddress ${urls[i]} failed`);\n\n if (++i < urls.length) {\n return tryConnectToAddress(urls[i], options).catch(onFail);\n }\n\n return Promise.resolve({\n State: 'Unavailable'\n });\n }\n\n return tryConnectToAddress(urls[i], options).catch(onFail);\n };\n\n self.deleteServer = (serverId) => {\n if (!serverId) {\n throw new Error('null serverId');\n }\n\n let server = credentialProvider.credentials().Servers.filter((s) => s.Id === serverId);\n server = server.length ? server[0] : null;\n\n return new Promise((resolve, reject) => {\n function onDone() {\n const credentials = credentialProvider.credentials();\n\n credentials.Servers = credentials.Servers.filter((s) => s.Id !== serverId);\n\n credentialProvider.credentials(credentials);\n resolve();\n }\n\n if (!server.ConnectServerId) {\n onDone();\n return;\n }\n });\n };\n }\n\n connect(options) {\n console.log('Begin connect');\n\n return this.getAvailableServers().then((servers) => {\n return this.connectToServers(servers, options);\n });\n }\n\n handleMessageReceived(msg) {\n const serverId = msg.ServerId;\n if (serverId) {\n const apiClient = this.getApiClient(serverId);\n if (apiClient) {\n if (typeof msg.Data === 'string') {\n try {\n msg.Data = JSON.parse(msg.Data);\n } catch (err) {\n console.log('unable to parse json content: ' + err);\n }\n }\n\n apiClient.handleMessageReceived(msg);\n }\n }\n }\n\n getApiClients() {\n const servers = this.getSavedServers();\n\n for (let i = 0, length = servers.length; i < length; i++) {\n const server = servers[i];\n if (server.Id) {\n this._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode));\n }\n }\n\n return this._apiClients;\n }\n\n getApiClient(item) {\n if (!item) {\n throw new Error('item or serverId cannot be null');\n }\n\n // Accept string + object\n if (item.ServerId) {\n item = item.ServerId;\n }\n\n return this._apiClients.filter((a) => {\n const serverInfo = a.serverInfo();\n\n // We have to keep this hack in here because of the addApiClient method\n return !serverInfo || serverInfo.Id === item;\n })[0];\n }\n\n minServerVersion(val) {\n if (val) {\n this._minServerVersion = val;\n }\n\n return this._minServerVersion;\n }\n}\n","import events from './events';\nimport appStorage from './appStorage';\n\nfunction ensure(instance, data) {\n if (!instance._credentials) {\n const json = instance.appStorage.getItem(instance.key) || '{}';\n\n console.log(`credentials initialized with: ${json}`);\n instance._credentials = JSON.parse(json);\n instance._credentials.Servers = instance._credentials.Servers || [];\n }\n}\n\nfunction set(instance, data) {\n if (data) {\n instance._credentials = data;\n instance.appStorage.setItem(instance.key, JSON.stringify(data));\n } else {\n instance.clear();\n }\n\n events.trigger(instance, 'credentialsupdated');\n}\n\nexport default class Credentials {\n constructor(key) {\n this.key = key || 'jellyfin_credentials';\n this.appStorage = appStorage;\n }\n\n clear() {\n this._credentials = null;\n this.appStorage.removeItem(this.key);\n }\n\n credentials(data) {\n if (data) {\n set(this, data);\n }\n\n ensure(this);\n return this._credentials;\n }\n\n addOrUpdateServer(list, server) {\n if (!server.Id) {\n throw new Error('Server.Id cannot be null or empty');\n }\n\n const existing = list.filter(({ Id }) => Id === server.Id)[0];\n\n if (existing) {\n // Merge the data\n existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0);\n\n existing.UserLinkType = server.UserLinkType;\n\n if (server.AccessToken) {\n existing.AccessToken = server.AccessToken;\n existing.UserId = server.UserId;\n }\n if (server.ExchangeToken) {\n existing.ExchangeToken = server.ExchangeToken;\n }\n if (server.RemoteAddress) {\n existing.RemoteAddress = server.RemoteAddress;\n }\n if (server.ManualAddress) {\n existing.ManualAddress = server.ManualAddress;\n }\n if (server.LocalAddress) {\n existing.LocalAddress = server.LocalAddress;\n }\n if (server.Name) {\n existing.Name = server.Name;\n }\n if (server.LastConnectionMode != null) {\n existing.LastConnectionMode = server.LastConnectionMode;\n }\n if (server.ConnectServerId) {\n existing.ConnectServerId = server.ConnectServerId;\n }\n\n return existing;\n } else {\n list.push(server);\n return server;\n }\n }\n}\n","import ApiClient from './apiClient';\nimport ApiClientCore from './apiClientCore';\nimport AppStorage from './appStorage';\nimport ConnectionManager from './connectionManager';\nimport Credentials from './credentials';\nimport Events from './events';\nconst fetch = require('node-fetch');\n\n\nexport default {\n ApiClient,\n ApiClientCore,\n AppStorage,\n ConnectionManager,\n Credentials,\n Events\n};\n"],"sourceRoot":""} |