mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 02:48:19 -07:00
Merge pull request #1007 from MrTimscampi/apiclient-be-gone
Remove API Client from the tree
This commit is contained in:
commit
a7241d39f6
@ -183,7 +183,9 @@ module.exports = {
|
||||
'Uint32Array',
|
||||
'Float32Array',
|
||||
'Float64Array',
|
||||
'Reflect'
|
||||
'Reflect',
|
||||
// Temporary while eslint-compat-plugin is buggy
|
||||
'document.querySelector'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@
|
||||
"hls.js": "^0.13.1",
|
||||
"howler": "^2.1.3",
|
||||
"intersection-observer": "^0.10.0",
|
||||
"jellyfin-apiclient": "^1.1.1",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"jquery": "^3.5.0",
|
||||
"jstree": "^3.3.7",
|
||||
@ -91,9 +92,9 @@
|
||||
"src/components/autoFocuser.js",
|
||||
"src/components/cardbuilder/cardBuilder.js",
|
||||
"src/components/filedownloader.js",
|
||||
"src/components/playback/mediasession.js",
|
||||
"src/components/images/imageLoader.js",
|
||||
"src/components/lazyloader/lazyloader-intersectionobserver.js",
|
||||
"src/components/playback/mediasession.js",
|
||||
"src/components/sanatizefilename.js",
|
||||
"src/components/scrollManager.js",
|
||||
"src/scripts/dfnshelper.js",
|
||||
|
@ -108,6 +108,7 @@ _define('page', function() {
|
||||
return page;
|
||||
});
|
||||
|
||||
// core-js
|
||||
var polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
_define('polyfill', function () {
|
||||
return polyfill;
|
||||
@ -152,3 +153,26 @@ var headroom = require('headroom.js/dist/headroom');
|
||||
_define('headroom', function () {
|
||||
return headroom;
|
||||
});
|
||||
|
||||
// apiclient
|
||||
var apiclient = require('jellyfin-apiclient');
|
||||
|
||||
_define('apiclient', function () {
|
||||
return apiclient.apiclient;
|
||||
});
|
||||
|
||||
_define('events', function () {
|
||||
return apiclient.Events;
|
||||
});
|
||||
|
||||
_define('credentialprovider', function () {
|
||||
return apiclient.Credentials;
|
||||
});
|
||||
|
||||
_define('connectionManagerFactory', function () {
|
||||
return apiclient.ConnectionManager;
|
||||
});
|
||||
|
||||
_define('appStorage', function () {
|
||||
return apiclient.AppStorage;
|
||||
});
|
||||
|
@ -109,7 +109,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
var now = Date.now();
|
||||
|
||||
if (window.performance && window.performance.now) {
|
||||
now = performance.now();
|
||||
now = performance.now(); // eslint-disable-line compat/compat
|
||||
}
|
||||
|
||||
if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) {
|
||||
|
@ -1,236 +0,0 @@
|
||||
//TODO: (vitorsemeano) modify this lines for webpack
|
||||
define(["libraries/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
if ("cordova" !== window.appMode && "android" !== window.appMode) {
|
||||
return ApiClient;
|
||||
}
|
||||
|
||||
function isLocalId(str) {
|
||||
return startsWith(str, localPrefix)
|
||||
}
|
||||
|
||||
function isLocalViewId(str) {
|
||||
return startsWith(str, localViewPrefix)
|
||||
}
|
||||
|
||||
function isTopLevelLocalViewId(str) {
|
||||
return "localview" === str
|
||||
}
|
||||
|
||||
function stripLocalPrefix(str) {
|
||||
var res = stripStart(str, localPrefix);
|
||||
return res = stripStart(res, localViewPrefix)
|
||||
}
|
||||
|
||||
function startsWith(str, find) {
|
||||
return !!(str && find && str.length > find.length && 0 === str.indexOf(find))
|
||||
}
|
||||
|
||||
function stripStart(str, find) {
|
||||
return startsWith(str, find) ? str.substr(find.length) : str
|
||||
}
|
||||
|
||||
function createEmptyList() {
|
||||
return {
|
||||
Items: [],
|
||||
TotalRecordCount: 0
|
||||
}
|
||||
}
|
||||
|
||||
function convertGuidToLocal(guid) {
|
||||
return guid ? isLocalId(guid) ? guid : "local:" + guid : null
|
||||
}
|
||||
|
||||
function adjustGuidProperties(downloadedItem) {
|
||||
downloadedItem.Id = convertGuidToLocal(downloadedItem.Id), downloadedItem.SeriesId = convertGuidToLocal(downloadedItem.SeriesId), downloadedItem.SeasonId = convertGuidToLocal(downloadedItem.SeasonId), downloadedItem.AlbumId = convertGuidToLocal(downloadedItem.AlbumId), downloadedItem.ParentId = convertGuidToLocal(downloadedItem.ParentId), downloadedItem.ParentThumbItemId = convertGuidToLocal(downloadedItem.ParentThumbItemId), downloadedItem.ParentPrimaryImageItemId = convertGuidToLocal(downloadedItem.ParentPrimaryImageItemId), downloadedItem.PrimaryImageItemId = convertGuidToLocal(downloadedItem.PrimaryImageItemId), downloadedItem.ParentLogoItemId = convertGuidToLocal(downloadedItem.ParentLogoItemId), downloadedItem.ParentBackdropItemId = convertGuidToLocal(downloadedItem.ParentBackdropItemId), downloadedItem.ParentBackdropImageTags = null
|
||||
}
|
||||
|
||||
function getLocalView(instance, serverId, userId) {
|
||||
return instance.getLocalFolders(serverId, userId).then(function(views) {
|
||||
var localView = null;
|
||||
return views.length > 0 && (localView = {
|
||||
Name: instance.downloadsTitleText || "Downloads",
|
||||
ServerId: serverId,
|
||||
Id: "localview",
|
||||
Type: "localview",
|
||||
IsFolder: !0
|
||||
}), Promise.resolve(localView)
|
||||
})
|
||||
}
|
||||
|
||||
function ApiClientEx(serverAddress, clientName, applicationVersion, deviceName, deviceId) {
|
||||
ApiClient.call(this, serverAddress, clientName, applicationVersion, deviceName, deviceId)
|
||||
}
|
||||
var localPrefix = "local:",
|
||||
localViewPrefix = "localview:";
|
||||
return Object.assign(ApiClientEx.prototype, ApiClient.prototype), ApiClientEx.prototype.getPlaybackInfo = function(itemId, options, deviceProfile) {
|
||||
var onFailure = function() {
|
||||
return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile)
|
||||
};
|
||||
if (isLocalId(itemId)) return localassetmanager.getLocalItem(this.serverId(), stripLocalPrefix(itemId)).then(function(item) {
|
||||
return {
|
||||
MediaSources: item.Item.MediaSources.map(function(m) {
|
||||
return m.SupportsDirectPlay = !0, m.SupportsDirectStream = !1, m.SupportsTranscoding = !1, m.IsLocal = !0, m
|
||||
})
|
||||
}
|
||||
}, onFailure);
|
||||
var instance = this;
|
||||
return localassetmanager.getLocalItem(this.serverId(), itemId).then(function(item) {
|
||||
if (item) {
|
||||
var mediaSources = item.Item.MediaSources.map(function(m) {
|
||||
return m.SupportsDirectPlay = !0, m.SupportsDirectStream = !1, m.SupportsTranscoding = !1, m.IsLocal = !0, m
|
||||
});
|
||||
return localassetmanager.fileExists(item.LocalPath).then(function(exists) {
|
||||
if (exists) {
|
||||
var res = {
|
||||
MediaSources: mediaSources
|
||||
};
|
||||
return Promise.resolve(res)
|
||||
}
|
||||
return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile)
|
||||
}, onFailure)
|
||||
}
|
||||
return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile)
|
||||
}, onFailure)
|
||||
}, ApiClientEx.prototype.getItems = function(userId, options) {
|
||||
var i, serverInfo = this.serverInfo();
|
||||
if (serverInfo && "localview" === options.ParentId) return this.getLocalFolders(serverInfo.Id, userId).then(function(items) {
|
||||
var result = {
|
||||
Items: items,
|
||||
TotalRecordCount: items.length
|
||||
};
|
||||
return Promise.resolve(result)
|
||||
});
|
||||
if (serverInfo && options && (isLocalId(options.ParentId) || isLocalId(options.SeriesId) || isLocalId(options.SeasonId) || isLocalViewId(options.ParentId) || isLocalId(options.AlbumIds))) return localassetmanager.getViewItems(serverInfo.Id, userId, options).then(function(items) {
|
||||
items.forEach(function(item) {
|
||||
adjustGuidProperties(item)
|
||||
});
|
||||
var result = {
|
||||
Items: items,
|
||||
TotalRecordCount: items.length
|
||||
};
|
||||
return Promise.resolve(result)
|
||||
});
|
||||
if (options && options.ExcludeItemIds && options.ExcludeItemIds.length) {
|
||||
var exItems = options.ExcludeItemIds.split(",");
|
||||
for (i = 0; i < exItems.length; i++)
|
||||
if (isLocalId(exItems[i])) return Promise.resolve(createEmptyList())
|
||||
} else if (options && options.Ids && options.Ids.length) {
|
||||
var ids = options.Ids.split(","),
|
||||
hasLocal = !1;
|
||||
for (i = 0; i < ids.length; i++) isLocalId(ids[i]) && (hasLocal = !0);
|
||||
if (hasLocal) return localassetmanager.getItemsFromIds(serverInfo.Id, ids).then(function(items) {
|
||||
items.forEach(function(item) {
|
||||
adjustGuidProperties(item)
|
||||
});
|
||||
var result = {
|
||||
Items: items,
|
||||
TotalRecordCount: items.length
|
||||
};
|
||||
return Promise.resolve(result)
|
||||
})
|
||||
}
|
||||
return ApiClient.prototype.getItems.call(this, userId, options)
|
||||
}, ApiClientEx.prototype.getUserViews = function(options, userId) {
|
||||
var instance = this;
|
||||
options = options || {};
|
||||
var basePromise = ApiClient.prototype.getUserViews.call(instance, options, userId);
|
||||
return options.enableLocalView ? basePromise.then(function(result) {
|
||||
var serverInfo = instance.serverInfo();
|
||||
return serverInfo ? getLocalView(instance, serverInfo.Id, userId).then(function(localView) {
|
||||
return localView && (result.Items.push(localView), result.TotalRecordCount++), Promise.resolve(result)
|
||||
}) : Promise.resolve(result)
|
||||
}) : basePromise
|
||||
}, ApiClientEx.prototype.getItem = function(userId, itemId) {
|
||||
if (!itemId) throw new Error("null itemId");
|
||||
itemId && (itemId = itemId.toString());
|
||||
var serverInfo;
|
||||
return isTopLevelLocalViewId(itemId) && (serverInfo = this.serverInfo()) ? getLocalView(this, serverInfo.Id, userId) : isLocalViewId(itemId) && (serverInfo = this.serverInfo()) ? this.getLocalFolders(serverInfo.Id, userId).then(function(items) {
|
||||
var views = items.filter(function(item) {
|
||||
return item.Id === itemId
|
||||
});
|
||||
return views.length > 0 ? Promise.resolve(views[0]) : Promise.reject()
|
||||
}) : isLocalId(itemId) && (serverInfo = this.serverInfo()) ? localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(itemId)).then(function(item) {
|
||||
return adjustGuidProperties(item.Item), Promise.resolve(item.Item)
|
||||
}) : ApiClient.prototype.getItem.call(this, userId, itemId)
|
||||
}, ApiClientEx.prototype.getLocalFolders = function(userId) {
|
||||
var serverInfo = this.serverInfo();
|
||||
return userId = userId || serverInfo.UserId, localassetmanager.getViews(serverInfo.Id, userId)
|
||||
}, ApiClientEx.prototype.getNextUpEpisodes = function(options) {
|
||||
return options.SeriesId && isLocalId(options.SeriesId) ? Promise.resolve(createEmptyList()) : ApiClient.prototype.getNextUpEpisodes.call(this, options)
|
||||
}, ApiClientEx.prototype.getSeasons = function(itemId, options) {
|
||||
return isLocalId(itemId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Season", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : ApiClient.prototype.getSeasons.call(this, itemId, options)
|
||||
}, ApiClientEx.prototype.getEpisodes = function(itemId, options) {
|
||||
return isLocalId(options.SeasonId) || isLocalId(options.seasonId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Episode", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : isLocalId(itemId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Episode", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : ApiClient.prototype.getEpisodes.call(this, itemId, options)
|
||||
}, ApiClientEx.prototype.getLatestOfflineItems = function(options) {
|
||||
options.SortBy = "DateCreated", options.SortOrder = "Descending";
|
||||
var serverInfo = this.serverInfo();
|
||||
return serverInfo ? localassetmanager.getViewItems(serverInfo.Id, null, options).then(function(items) {
|
||||
return items.forEach(function(item) {
|
||||
adjustGuidProperties(item)
|
||||
}), Promise.resolve(items)
|
||||
}) : Promise.resolve([])
|
||||
}, ApiClientEx.prototype.getThemeMedia = function(userId, itemId, inherit) {
|
||||
return isLocalViewId(itemId) || isLocalId(itemId) || isTopLevelLocalViewId(itemId) ? Promise.reject() : ApiClient.prototype.getThemeMedia.call(this, userId, itemId, inherit)
|
||||
}, ApiClientEx.prototype.getSpecialFeatures = function(userId, itemId) {
|
||||
return isLocalId(itemId) ? Promise.resolve([]) : ApiClient.prototype.getSpecialFeatures.call(this, userId, itemId)
|
||||
}, ApiClientEx.prototype.getSimilarItems = function(itemId, options) {
|
||||
return isLocalId(itemId) ? Promise.resolve(createEmptyList()) : ApiClient.prototype.getSimilarItems.call(this, itemId, options)
|
||||
}, ApiClientEx.prototype.updateFavoriteStatus = function(userId, itemId, isFavorite) {
|
||||
return isLocalId(itemId) ? Promise.resolve() : ApiClient.prototype.updateFavoriteStatus.call(this, userId, itemId, isFavorite)
|
||||
}, ApiClientEx.prototype.getScaledImageUrl = function(itemId, options) {
|
||||
if (isLocalId(itemId) || options && options.itemid && isLocalId(options.itemid)) {
|
||||
var serverInfo = this.serverInfo(),
|
||||
id = stripLocalPrefix(itemId);
|
||||
return localassetmanager.getImageUrl(serverInfo.Id, id, options)
|
||||
}
|
||||
return ApiClient.prototype.getScaledImageUrl.call(this, itemId, options)
|
||||
}, ApiClientEx.prototype.reportPlaybackStart = function(options) {
|
||||
if (!options) throw new Error("null options");
|
||||
return isLocalId(options.ItemId) ? Promise.resolve() : ApiClient.prototype.reportPlaybackStart.call(this, options)
|
||||
}, ApiClientEx.prototype.reportPlaybackProgress = function(options) {
|
||||
if (!options) throw new Error("null options");
|
||||
if (isLocalId(options.ItemId)) {
|
||||
var serverInfo = this.serverInfo();
|
||||
return serverInfo ? localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(options.ItemId)).then(function(item) {
|
||||
var libraryItem = item.Item;
|
||||
return "Video" === libraryItem.MediaType || "AudioBook" === libraryItem.Type ? (libraryItem.UserData = libraryItem.UserData || {}, libraryItem.UserData.PlaybackPositionTicks = options.PositionTicks, libraryItem.UserData.PlayedPercentage = Math.min(libraryItem.RunTimeTicks ? (options.PositionTicks || 0) / libraryItem.RunTimeTicks * 100 : 0, 100), localassetmanager.addOrUpdateLocalItem(item)) : Promise.resolve()
|
||||
}) : Promise.resolve()
|
||||
}
|
||||
return ApiClient.prototype.reportPlaybackProgress.call(this, options)
|
||||
}, ApiClientEx.prototype.reportPlaybackStopped = function(options) {
|
||||
if (!options) throw new Error("null options");
|
||||
if (isLocalId(options.ItemId)) {
|
||||
var serverInfo = this.serverInfo(),
|
||||
action = {
|
||||
Date: (new Date).getTime(),
|
||||
ItemId: stripLocalPrefix(options.ItemId),
|
||||
PositionTicks: options.PositionTicks,
|
||||
ServerId: serverInfo.Id,
|
||||
Type: 0,
|
||||
UserId: this.getCurrentUserId()
|
||||
};
|
||||
return localassetmanager.recordUserAction(action)
|
||||
}
|
||||
return ApiClient.prototype.reportPlaybackStopped.call(this, options)
|
||||
}, ApiClientEx.prototype.getIntros = function(itemId) {
|
||||
return isLocalId(itemId) ? Promise.resolve({
|
||||
Items: [],
|
||||
TotalRecordCount: 0
|
||||
}) : ApiClient.prototype.getIntros.call(this, itemId)
|
||||
}, ApiClientEx.prototype.getInstantMixFromItem = function(itemId, options) {
|
||||
return isLocalId(itemId) ? Promise.resolve({
|
||||
Items: [],
|
||||
TotalRecordCount: 0
|
||||
}) : ApiClient.prototype.getInstantMixFromItem.call(this, itemId, options)
|
||||
}, ApiClientEx.prototype.getItemDownloadUrl = function(itemId) {
|
||||
if (isLocalId(itemId)) {
|
||||
var serverInfo = this.serverInfo();
|
||||
if (serverInfo) return localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(itemId)).then(function(item) {
|
||||
return Promise.resolve(item.LocalPath)
|
||||
})
|
||||
}
|
||||
return ApiClient.prototype.getItemDownloadUrl.call(this, itemId)
|
||||
}, ApiClientEx
|
||||
});
|
@ -1,53 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.error("cannot put to a cache: " + e);
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
if (instance.cache) {
|
||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail);
|
||||
}
|
||||
}
|
||||
|
||||
function onCacheOpened(result) {
|
||||
this.cache = result;
|
||||
this.localData = {};
|
||||
}
|
||||
|
||||
function MyStore() {
|
||||
|
||||
this.setItem = function(name, value) {
|
||||
localStorage.setItem(name, value);
|
||||
|
||||
if (this.localData && this.localData[name] !== value) {
|
||||
this.localData[name] = value;
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
this.getItem = function(name) {
|
||||
return localStorage.getItem(name);
|
||||
};
|
||||
|
||||
this.removeItem = function(name) {
|
||||
localStorage.removeItem(name);
|
||||
|
||||
if (this.localData) {
|
||||
delete this.localData[name];
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
if (self.caches) {
|
||||
self.caches.open("embydata").then(onCacheOpened.bind(this));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("error opening cache: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
return new MyStore;
|
||||
});
|
@ -1,807 +0,0 @@
|
||||
define(["events", "apiclient", "appStorage"], function (events, apiClientFactory, appStorage) {
|
||||
"use strict";
|
||||
|
||||
function getServerAddress(server, mode) {
|
||||
switch (mode) {
|
||||
case ConnectionMode.Local:
|
||||
return server.LocalAddress;
|
||||
|
||||
case ConnectionMode.Manual:
|
||||
return server.ManualAddress;
|
||||
|
||||
case ConnectionMode.Remote:
|
||||
return server.RemoteAddress;
|
||||
|
||||
default:
|
||||
return server.ManualAddress || server.LocalAddress || server.RemoteAddress;
|
||||
}
|
||||
}
|
||||
|
||||
function paramsToString(params) {
|
||||
var values = [];
|
||||
|
||||
for (var key in params) {
|
||||
var value = params[key];
|
||||
|
||||
if (null !== value && void 0 !== value && "" !== value) {
|
||||
values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
||||
}
|
||||
}
|
||||
|
||||
return values.join("&");
|
||||
}
|
||||
|
||||
function resolveFailure(instance, resolve) {
|
||||
resolve({
|
||||
State: "Unavailable",
|
||||
});
|
||||
}
|
||||
|
||||
function mergeServers(credentialProvider, list1, list2) {
|
||||
for (var i = 0, length = list2.length; i < length; i++) {
|
||||
credentialProvider.addOrUpdateServer(list1, list2[i]);
|
||||
}
|
||||
|
||||
return list1;
|
||||
}
|
||||
|
||||
function updateServerInfo(server, systemInfo) {
|
||||
server.Name = systemInfo.ServerName;
|
||||
if (systemInfo.Id) {
|
||||
server.Id = systemInfo.Id;
|
||||
}
|
||||
|
||||
if (systemInfo.LocalAddress) {
|
||||
server.LocalAddress = systemInfo.LocalAddress;
|
||||
}
|
||||
}
|
||||
|
||||
function getEmbyServerUrl(baseUrl, handler) {
|
||||
return baseUrl + "/" + handler;
|
||||
}
|
||||
|
||||
function getFetchPromise(request) {
|
||||
var headers = request.headers || {};
|
||||
|
||||
if ("json" === request.dataType) {
|
||||
headers.accept = "application/json";
|
||||
}
|
||||
|
||||
var fetchRequest = {
|
||||
headers: headers,
|
||||
method: request.type,
|
||||
credentials: "same-origin"
|
||||
};
|
||||
var contentType = request.contentType;
|
||||
|
||||
if (request.data) {
|
||||
if ("string" == typeof request.data) {
|
||||
fetchRequest.body = request.data;
|
||||
} else {
|
||||
fetchRequest.body = paramsToString(request.data);
|
||||
contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8";
|
||||
}
|
||||
}
|
||||
|
||||
if (contentType) {
|
||||
headers["Content-Type"] = contentType;
|
||||
}
|
||||
|
||||
if (request.timeout) {
|
||||
return fetchWithTimeout(request.url, fetchRequest, request.timeout);
|
||||
}
|
||||
|
||||
return fetch(request.url, fetchRequest);
|
||||
}
|
||||
|
||||
function fetchWithTimeout(url, options, timeoutMs) {
|
||||
console.debug("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url);
|
||||
return new Promise(function (resolve, reject) {
|
||||
var timeout = setTimeout(reject, timeoutMs);
|
||||
options = options || {};
|
||||
options.credentials = "same-origin";
|
||||
fetch(url, options).then(function (response) {
|
||||
clearTimeout(timeout);
|
||||
console.debug("fetchWithTimeout: succeeded connecting to url: " + url);
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
clearTimeout(timeout);
|
||||
console.error("fetchWithTimeout: timed out connecting to url: " + url);
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ajax(request) {
|
||||
if (!request) {
|
||||
throw new Error("Request cannot be null");
|
||||
}
|
||||
|
||||
request.headers = request.headers || {};
|
||||
console.debug("ConnectionManager requesting url: " + request.url);
|
||||
return getFetchPromise(request).then(function (response) {
|
||||
console.debug("ConnectionManager response status: " + response.status + ", url: " + request.url);
|
||||
|
||||
if (response.status < 400) {
|
||||
if ("json" === request.dataType || "application/json" === request.headers.accept) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
return Promise.reject(response);
|
||||
}, function (err) {
|
||||
console.error("ConnectionManager request failed to url: " + request.url);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var reg = new RegExp(strReplace, "ig");
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
function normalizeAddress(address) {
|
||||
address = address.trim();
|
||||
|
||||
if (0 !== address.toLowerCase().indexOf("http")) {
|
||||
address = "http://" + address;
|
||||
}
|
||||
|
||||
address = replaceAll(address, "Http:", "http:");
|
||||
address = replaceAll(address, "Https:", "https:");
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
function stringEqualsIgnoreCase(str1, str2) {
|
||||
return (str1 || "").toLowerCase() === (str2 || "").toLowerCase();
|
||||
}
|
||||
|
||||
function compareVersions(a, b) {
|
||||
a = a.split(".");
|
||||
b = b.split(".");
|
||||
|
||||
for (var i = 0, length = Math.max(a.length, b.length); i < length; i++) {
|
||||
var aVal = parseInt(a[i] || "0");
|
||||
var bVal = parseInt(b[i] || "0");
|
||||
|
||||
if (aVal < bVal) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aVal > bVal) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
var defaultTimeout = 20000;
|
||||
var ConnectionMode = {
|
||||
Local: 0,
|
||||
Remote: 1,
|
||||
Manual: 2
|
||||
};
|
||||
|
||||
var ConnectionManager = function (credentialProvider, appName, appVersion, deviceName, deviceId, capabilities) {
|
||||
|
||||
function onAuthenticated(apiClient, result, options, saveCredentials) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
var servers = credentials.Servers.filter(function (s) {
|
||||
return s.Id === result.ServerId;
|
||||
});
|
||||
var server = servers.length ? servers[0] : apiClient.serverInfo();
|
||||
|
||||
if (false !== options.updateDateLastAccessed) {
|
||||
server.DateLastAccessed = new Date().getTime();
|
||||
}
|
||||
|
||||
server.Id = result.ServerId;
|
||||
|
||||
if (saveCredentials) {
|
||||
server.UserId = result.User.Id;
|
||||
server.AccessToken = result.AccessToken;
|
||||
} else {
|
||||
server.UserId = null;
|
||||
server.AccessToken = null;
|
||||
}
|
||||
|
||||
credentialProvider.addOrUpdateServer(credentials.Servers, server);
|
||||
credentialProvider.credentials(credentials);
|
||||
apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
|
||||
apiClient.serverInfo(server);
|
||||
afterConnected(apiClient, options);
|
||||
return onLocalUserSignIn(server, apiClient.serverAddress(), result.User);
|
||||
}
|
||||
|
||||
function afterConnected(apiClient, options) {
|
||||
options = options || {};
|
||||
|
||||
if (false !== options.reportCapabilities) {
|
||||
apiClient.reportCapabilities(capabilities);
|
||||
}
|
||||
|
||||
apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
|
||||
|
||||
if (false !== options.enableWebSocket) {
|
||||
console.debug("calling apiClient.ensureWebSocket");
|
||||
apiClient.ensureWebSocket();
|
||||
}
|
||||
}
|
||||
|
||||
function onLocalUserSignIn(server, serverUrl, user) {
|
||||
self._getOrAddApiClient(server, serverUrl);
|
||||
|
||||
var promise = self.onLocalUserSignedIn ? self.onLocalUserSignedIn.call(self, user) : Promise.resolve();
|
||||
return promise.then(function () {
|
||||
events.trigger(self, "localusersignedin", [user])
|
||||
})
|
||||
}
|
||||
|
||||
function validateAuthentication(server, serverUrl) {
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: getEmbyServerUrl(serverUrl, "System/Info"),
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-MediaBrowser-Token": server.AccessToken
|
||||
}
|
||||
}).then(function (systemInfo) {
|
||||
updateServerInfo(server, systemInfo);
|
||||
return Promise.resolve();
|
||||
}, function () {
|
||||
server.UserId = null;
|
||||
server.AccessToken = null;
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function getImageUrl(localUser) {
|
||||
if (localUser && localUser.PrimaryImageTag) {
|
||||
return {
|
||||
url: self.getApiClient(localUser).getUserImageUrl(localUser.Id, {
|
||||
tag: localUser.PrimaryImageTag,
|
||||
type: "Primary"
|
||||
}),
|
||||
supportsParams: true
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
url: null,
|
||||
supportsParams: false
|
||||
};
|
||||
}
|
||||
|
||||
function logoutOfServer(apiClient) {
|
||||
var serverInfo = apiClient.serverInfo() || {};
|
||||
var logoutInfo = {
|
||||
serverId: serverInfo.Id
|
||||
};
|
||||
return apiClient.logout().then(function () {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo]);
|
||||
}, function () {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo]);
|
||||
});
|
||||
}
|
||||
|
||||
function findServers() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var onFinish = function (foundServers) {
|
||||
var servers = foundServers.map(function (foundServer) {
|
||||
var info = {
|
||||
Id: foundServer.Id,
|
||||
LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address,
|
||||
Name: foundServer.Name
|
||||
};
|
||||
info.LastConnectionMode = info.ManualAddress ? ConnectionMode.Manual : ConnectionMode.Local;
|
||||
return info;
|
||||
});
|
||||
resolve(servers);
|
||||
};
|
||||
|
||||
if (window.NativeShell && typeof window.NativeShell.findServers === 'function') {
|
||||
window.NativeShell.findServers(1e3).then(onFinish, function () {
|
||||
onFinish([]);
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function convertEndpointAddressToManualAddress(info) {
|
||||
if (info.Address && info.EndpointAddress) {
|
||||
var address = info.EndpointAddress.split(":")[0];
|
||||
var parts = info.Address.split(":");
|
||||
|
||||
if (parts.length > 1) {
|
||||
var portString = parts[parts.length - 1];
|
||||
|
||||
if (!isNaN(parseInt(portString))) {
|
||||
address += ":" + portString;
|
||||
}
|
||||
}
|
||||
|
||||
return normalizeAddress(address);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTryConnectPromise(url, connectionMode, state, resolve, reject) {
|
||||
console.debug("getTryConnectPromise " + url);
|
||||
ajax({
|
||||
url: getEmbyServerUrl(url, "system/info/public"),
|
||||
timeout: defaultTimeout,
|
||||
type: "GET",
|
||||
dataType: "json"
|
||||
}).then(function (result) {
|
||||
if (!state.resolved) {
|
||||
state.resolved = true;
|
||||
console.debug("Reconnect succeeded to " + url);
|
||||
resolve({
|
||||
url: url,
|
||||
connectionMode: connectionMode,
|
||||
data: result
|
||||
});
|
||||
}
|
||||
}, function () {
|
||||
if (!state.resolved) {
|
||||
console.error("Reconnect failed to " + url);
|
||||
|
||||
if (++state.rejects >= state.numAddresses) {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryReconnect(serverInfo) {
|
||||
var addresses = [];
|
||||
var addressesStrings = [];
|
||||
|
||||
if (!serverInfo.manualAddressOnly && serverInfo.LocalAddress && -1 === addressesStrings.indexOf(serverInfo.LocalAddress)) {
|
||||
addresses.push({
|
||||
url: serverInfo.LocalAddress,
|
||||
mode: ConnectionMode.Local,
|
||||
timeout: 0
|
||||
});
|
||||
addressesStrings.push(addresses[addresses.length - 1].url);
|
||||
}
|
||||
|
||||
if (serverInfo.ManualAddress && -1 === addressesStrings.indexOf(serverInfo.ManualAddress)) {
|
||||
addresses.push({
|
||||
url: serverInfo.ManualAddress,
|
||||
mode: ConnectionMode.Manual,
|
||||
timeout: 100
|
||||
});
|
||||
addressesStrings.push(addresses[addresses.length - 1].url);
|
||||
}
|
||||
|
||||
if (!serverInfo.manualAddressOnly && serverInfo.RemoteAddress && -1 === addressesStrings.indexOf(serverInfo.RemoteAddress)) {
|
||||
addresses.push({
|
||||
url: serverInfo.RemoteAddress,
|
||||
mode: ConnectionMode.Remote,
|
||||
timeout: 200
|
||||
});
|
||||
addressesStrings.push(addresses[addresses.length - 1].url);
|
||||
}
|
||||
|
||||
console.debug("tryReconnect: " + addressesStrings.join("|"));
|
||||
return new Promise(function (resolve, reject) {
|
||||
var state = {};
|
||||
state.numAddresses = addresses.length;
|
||||
state.rejects = 0;
|
||||
addresses.map(function (url) {
|
||||
setTimeout(function () {
|
||||
if (!state.resolved) {
|
||||
getTryConnectPromise(url.url, url.mode, state, resolve, reject);
|
||||
}
|
||||
}, url.timeout);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSuccessfulConnection(server, systemInfo, connectionMode, serverUrl, options, resolve) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
options = options || {};
|
||||
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, true, options, resolve);
|
||||
}
|
||||
|
||||
function afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, verifyLocalAuthentication, options, resolve) {
|
||||
options = options || {};
|
||||
if (false === options.enableAutoLogin) {
|
||||
server.UserId = null;
|
||||
server.AccessToken = null;
|
||||
} else if (verifyLocalAuthentication && server.AccessToken && false !== options.enableAutoLogin) {
|
||||
return void validateAuthentication(server, serverUrl).then(function () {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, false, options, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
updateServerInfo(server, systemInfo);
|
||||
server.LastConnectionMode = connectionMode;
|
||||
|
||||
if (false !== options.updateDateLastAccessed) {
|
||||
server.DateLastAccessed = new Date().getTime();
|
||||
}
|
||||
|
||||
credentialProvider.addOrUpdateServer(credentials.Servers, server);
|
||||
credentialProvider.credentials(credentials);
|
||||
var result = {
|
||||
Servers: []
|
||||
};
|
||||
result.ApiClient = self._getOrAddApiClient(server, serverUrl);
|
||||
result.ApiClient.setSystemInfo(systemInfo);
|
||||
result.State = server.AccessToken && false !== options.enableAutoLogin ? "SignedIn" : "ServerSignIn";
|
||||
result.Servers.push(server);
|
||||
result.ApiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
|
||||
result.ApiClient.updateServerInfo(server, serverUrl);
|
||||
|
||||
var resolveActions = function () {
|
||||
resolve(result);
|
||||
events.trigger(self, "connected", [result]);
|
||||
};
|
||||
|
||||
if ("SignedIn" === result.State) {
|
||||
afterConnected(result.ApiClient, options);
|
||||
result.ApiClient.getCurrentUser().then(function (user) {
|
||||
onLocalUserSignIn(server, serverUrl, user).then(resolveActions, resolveActions);
|
||||
}, resolveActions);
|
||||
} else {
|
||||
resolveActions();
|
||||
}
|
||||
}
|
||||
|
||||
console.debug("Begin ConnectionManager constructor");
|
||||
var self = this;
|
||||
this._apiClients = [];
|
||||
self._minServerVersion = "3.2.33";
|
||||
|
||||
self.appVersion = function () {
|
||||
return appVersion;
|
||||
};
|
||||
|
||||
self.appName = function () {
|
||||
return appName;
|
||||
};
|
||||
|
||||
self.capabilities = function () {
|
||||
return capabilities;
|
||||
};
|
||||
|
||||
self.deviceId = function () {
|
||||
return deviceId;
|
||||
};
|
||||
|
||||
self.credentialProvider = function () {
|
||||
return credentialProvider;
|
||||
};
|
||||
|
||||
self.getServerInfo = function (id) {
|
||||
return credentialProvider.credentials().Servers.filter(function (s) {
|
||||
return s.Id === id;
|
||||
})[0];
|
||||
};
|
||||
|
||||
self.getLastUsedServer = function () {
|
||||
var servers = credentialProvider.credentials().Servers;
|
||||
servers.sort(function (a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0);
|
||||
});
|
||||
|
||||
if (servers.length) {
|
||||
return servers[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
self.addApiClient = function (apiClient) {
|
||||
self._apiClients.push(apiClient);
|
||||
|
||||
var existingServers = credentialProvider.credentials().Servers.filter(function (s) {
|
||||
return stringEqualsIgnoreCase(s.ManualAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.LocalAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.RemoteAddress, apiClient.serverAddress());
|
||||
});
|
||||
var existingServer = existingServers.length ? existingServers[0] : apiClient.serverInfo();
|
||||
|
||||
existingServer.DateLastAccessed = new Date().getTime();
|
||||
existingServer.LastConnectionMode = ConnectionMode.Manual;
|
||||
existingServer.ManualAddress = apiClient.serverAddress();
|
||||
if (apiClient.manualAddressOnly) {
|
||||
existingServer.manualAddressOnly = true;
|
||||
}
|
||||
apiClient.serverInfo(existingServer);
|
||||
apiClient.onAuthenticated = function (instance, result) {
|
||||
return onAuthenticated(instance, result, {}, true);
|
||||
};
|
||||
if (!existingServers.length) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.Servers = [existingServer];
|
||||
credentialProvider.credentials(credentials);
|
||||
}
|
||||
|
||||
events.trigger(self, "apiclientcreated", [apiClient]);
|
||||
};
|
||||
|
||||
self.clearData = function () {
|
||||
console.debug("connection manager clearing data");
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.Servers = [];
|
||||
credentialProvider.credentials(credentials);
|
||||
};
|
||||
|
||||
self._getOrAddApiClient = function (server, serverUrl) {
|
||||
var apiClient = self.getApiClient(server.Id);
|
||||
|
||||
if (!apiClient) {
|
||||
apiClient = new apiClientFactory(serverUrl, appName, appVersion, deviceName, deviceId);
|
||||
self._apiClients.push(apiClient);
|
||||
apiClient.serverInfo(server);
|
||||
apiClient.onAuthenticated = function (instance, result) {
|
||||
return onAuthenticated(instance, result, {}, true);
|
||||
};
|
||||
|
||||
events.trigger(self, "apiclientcreated", [apiClient]);
|
||||
}
|
||||
|
||||
console.debug("returning instance from getOrAddApiClient");
|
||||
return apiClient;
|
||||
};
|
||||
|
||||
self.getOrCreateApiClient = function (serverId) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
var servers = credentials.Servers.filter(function (s) {
|
||||
return stringEqualsIgnoreCase(s.Id, serverId);
|
||||
});
|
||||
|
||||
if (!servers.length) {
|
||||
throw new Error("Server not found: " + serverId);
|
||||
}
|
||||
|
||||
var server = servers[0];
|
||||
return self._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode));
|
||||
};
|
||||
|
||||
self.user = function (apiClient) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
function onLocalUserDone(e) {
|
||||
if (apiClient && apiClient.getCurrentUserId()) {
|
||||
apiClient.getCurrentUser().then(function (u) {
|
||||
localUser = u;
|
||||
var image = getImageUrl(localUser);
|
||||
resolve({
|
||||
localUser: localUser,
|
||||
name: localUser ? localUser.Name : null,
|
||||
imageUrl: image.url,
|
||||
supportsImageParams: image.supportsParams,
|
||||
});
|
||||
}, onLocalUserDone);
|
||||
}
|
||||
}
|
||||
var localUser;
|
||||
if (apiClient && apiClient.getCurrentUserId()) {
|
||||
onLocalUserDone();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.logout = function () {
|
||||
console.debug("begin connectionManager loguot");
|
||||
var promises = [];
|
||||
|
||||
for (var i = 0, length = self._apiClients.length; i < length; i++) {
|
||||
var apiClient = self._apiClients[i];
|
||||
|
||||
if (apiClient.accessToken()) {
|
||||
promises.push(logoutOfServer(apiClient));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(function () {
|
||||
var credentials = credentialProvider.credentials();
|
||||
var servers = credentials.Servers.filter(function (u) {
|
||||
return "Guest" !== u.UserLinkType;
|
||||
});
|
||||
|
||||
for (var j = 0, numServers = servers.length; j < numServers; j++) {
|
||||
var server = servers[j];
|
||||
server.UserId = null;
|
||||
server.AccessToken = null;
|
||||
server.ExchangeToken = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.getSavedServers = function () {
|
||||
var credentials = credentialProvider.credentials();
|
||||
var servers = credentials.Servers.slice(0);
|
||||
servers.sort(function (a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0);
|
||||
});
|
||||
return servers;
|
||||
};
|
||||
|
||||
self.getAvailableServers = function () {
|
||||
console.debug("begin getAvailableServers");
|
||||
var credentials = credentialProvider.credentials();
|
||||
return Promise.all([findServers()]).then(function (responses) {
|
||||
var foundServers = responses[0];
|
||||
var servers = credentials.Servers.slice(0);
|
||||
mergeServers(credentialProvider, servers, foundServers);
|
||||
servers.sort(function (a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0);
|
||||
});
|
||||
credentials.Servers = servers;
|
||||
credentialProvider.credentials(credentials);
|
||||
return servers;
|
||||
});
|
||||
};
|
||||
|
||||
self.connectToServers = function (servers, options) {
|
||||
console.debug("begin connectToServers, with " + servers.length + " servers");
|
||||
var firstServer = servers.length ? servers[0] : null;
|
||||
|
||||
if (firstServer) {
|
||||
return self.connectToServer(firstServer, options).then(function (result) {
|
||||
if ("Unavailable" === result.State) {
|
||||
result.State = "ServerSelection";
|
||||
}
|
||||
|
||||
console.debug("resolving connectToServers with result.State: " + result.State);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
Servers: servers,
|
||||
State: "ServerSelection"
|
||||
});
|
||||
};
|
||||
|
||||
self.connectToServer = function (server, options) {
|
||||
console.debug("begin connectToServer");
|
||||
return new Promise(function (resolve, reject) {
|
||||
options = options || {};
|
||||
tryReconnect(server).then(function (result) {
|
||||
var serverUrl = result.url;
|
||||
var connectionMode = result.connectionMode;
|
||||
result = result.data;
|
||||
|
||||
if (1 === compareVersions(self.minServerVersion(), result.Version)) {
|
||||
console.debug("minServerVersion requirement not met. Server version: " + result.Version);
|
||||
resolve({
|
||||
State: "ServerUpdateNeeded",
|
||||
Servers: [server]
|
||||
});
|
||||
} else {
|
||||
if (server.Id && result.Id !== server.Id) {
|
||||
console.debug("http request succeeded, but found a different server Id than what was expected");
|
||||
resolveFailure(self, resolve);
|
||||
} else {
|
||||
onSuccessfulConnection(server, result, connectionMode, serverUrl, options, resolve);
|
||||
}
|
||||
}
|
||||
}, function () {
|
||||
resolveFailure(self, resolve);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.connectToAddress = function (address, options) {
|
||||
function onFail() {
|
||||
console.error("connectToAddress " + address + " failed");
|
||||
return Promise.resolve({
|
||||
State: "Unavailable",
|
||||
});
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
address = normalizeAddress(address);
|
||||
var instance = this;
|
||||
var server = {
|
||||
ManualAddress: address,
|
||||
LastConnectionMode: ConnectionMode.Manual
|
||||
};
|
||||
return self.connectToServer(server, options).catch(onFail);
|
||||
};
|
||||
|
||||
self.deleteServer = function (serverId) {
|
||||
if (!serverId) {
|
||||
throw new Error("null serverId");
|
||||
}
|
||||
|
||||
var server = credentialProvider.credentials().Servers.filter(function (s) {
|
||||
return s.Id === serverId;
|
||||
});
|
||||
server = server.length ? server[0] : null;
|
||||
return new Promise(function (resolve, reject) {
|
||||
function onDone() {
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.Servers = credentials.Servers.filter(function (s) {
|
||||
return s.Id !== serverId;
|
||||
});
|
||||
credentialProvider.credentials(credentials);
|
||||
resolve();
|
||||
}
|
||||
|
||||
if (!server.ConnectServerId) {
|
||||
return void onDone();
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
ConnectionManager.prototype.connect = function (options) {
|
||||
console.debug("begin connect");
|
||||
var instance = this;
|
||||
return instance.getAvailableServers().then(function (servers) {
|
||||
return instance.connectToServers(servers, options);
|
||||
});
|
||||
};
|
||||
|
||||
ConnectionManager.prototype.getApiClients = function () {
|
||||
var servers = this.getSavedServers();
|
||||
|
||||
for (var i = 0, length = servers.length; i < length; i++) {
|
||||
var server = servers[i];
|
||||
|
||||
if (server.Id) {
|
||||
this._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode));
|
||||
}
|
||||
}
|
||||
|
||||
return this._apiClients;
|
||||
};
|
||||
|
||||
ConnectionManager.prototype.getApiClient = function (item) {
|
||||
if (!item) {
|
||||
throw new Error("item or serverId cannot be null");
|
||||
}
|
||||
|
||||
if (item.ServerId) {
|
||||
item = item.ServerId;
|
||||
}
|
||||
|
||||
return this._apiClients.filter(function (a) {
|
||||
var serverInfo = a.serverInfo();
|
||||
return !serverInfo || serverInfo.Id === item;
|
||||
})[0];
|
||||
};
|
||||
|
||||
ConnectionManager.prototype.minServerVersion = function (val) {
|
||||
if (val) {
|
||||
this._minServerVersion = val;
|
||||
}
|
||||
|
||||
return this._minServerVersion;
|
||||
};
|
||||
|
||||
ConnectionManager.prototype.handleMessageReceived = function (msg) {
|
||||
var serverId = msg.ServerId;
|
||||
|
||||
if (serverId) {
|
||||
var apiClient = this.getApiClient(serverId);
|
||||
|
||||
if (apiClient) {
|
||||
if ("string" == typeof msg.Data) {
|
||||
try {
|
||||
msg.Data = JSON.parse(msg.Data);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
apiClient.handleMessageReceived(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return ConnectionManager;
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
define(["events", "appStorage"], function(events, appStorage) {
|
||||
"use strict";
|
||||
|
||||
function ensure(instance, data) {
|
||||
if (!instance._credentials) {
|
||||
var json = appStorage.getItem(instance.key) || "{}";
|
||||
console.debug("credentials initialized with: " + json), instance._credentials = JSON.parse(json), instance._credentials.Servers = instance._credentials.Servers || []
|
||||
}
|
||||
}
|
||||
|
||||
function set(instance, data) {
|
||||
data ? (instance._credentials = data, appStorage.setItem(instance.key, JSON.stringify(data))) : instance.clear(), events.trigger(instance, "credentialsupdated")
|
||||
}
|
||||
|
||||
function Credentials(key) {
|
||||
this.key = key || "jellyfin_credentials"
|
||||
}
|
||||
return Credentials.prototype.clear = function() {
|
||||
this._credentials = null, appStorage.removeItem(this.key)
|
||||
}, Credentials.prototype.credentials = function(data) {
|
||||
return data && set(this, data), ensure(this), this._credentials
|
||||
}, Credentials.prototype.addOrUpdateServer = function(list, server) {
|
||||
if (!server.Id) throw new Error("Server.Id cannot be null or empty");
|
||||
var existing = list.filter(function(s) {
|
||||
return s.Id === server.Id
|
||||
})[0];
|
||||
return existing ? (existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0), existing.UserLinkType = server.UserLinkType, server.AccessToken && (existing.AccessToken = server.AccessToken, existing.UserId = server.UserId), server.ExchangeToken && (existing.ExchangeToken = server.ExchangeToken), server.RemoteAddress && (existing.RemoteAddress = server.RemoteAddress), server.ManualAddress && (existing.ManualAddress = server.ManualAddress), server.LocalAddress && (existing.LocalAddress = server.LocalAddress), server.Name && (existing.Name = server.Name), null != server.LastConnectionMode && (existing.LastConnectionMode = server.LastConnectionMode), server.ConnectServerId && (existing.ConnectServerId = server.ConnectServerId), existing) : (list.push(server), server)
|
||||
}, Credentials
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function getCallbacks(obj, name) {
|
||||
if (!obj) throw new Error("obj cannot be null!");
|
||||
obj._callbacks = obj._callbacks || {};
|
||||
var list = obj._callbacks[name];
|
||||
return list || (obj._callbacks[name] = [], list = obj._callbacks[name]), list
|
||||
}
|
||||
return {
|
||||
on: function(obj, eventName, fn) {
|
||||
getCallbacks(obj, eventName).push(fn)
|
||||
},
|
||||
off: function(obj, eventName, fn) {
|
||||
var list = getCallbacks(obj, eventName),
|
||||
i = list.indexOf(fn); - 1 !== i && list.splice(i, 1)
|
||||
},
|
||||
trigger: function(obj, eventName) {
|
||||
var eventObject = {
|
||||
type: eventName
|
||||
},
|
||||
eventArgs = [];
|
||||
eventArgs.push(eventObject);
|
||||
for (var additionalArgs = arguments[2] || [], i = 0, length = additionalArgs.length; i < length; i++) eventArgs.push(additionalArgs[i]);
|
||||
getCallbacks(obj, eventName).slice(0).forEach(function(c) {
|
||||
c.apply(obj, eventArgs)
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
@ -1,406 +0,0 @@
|
||||
define(["filerepository", "itemrepository", "useractionrepository", "transfermanager"], function(filerepository, itemrepository, useractionrepository, transfermanager) {
|
||||
"use strict";
|
||||
|
||||
function getLocalItem(serverId, itemId) {
|
||||
return console.debug("localassetmanager: begin getLocalItem"), itemrepository.get(serverId, itemId)
|
||||
}
|
||||
|
||||
function recordUserAction(action) {
|
||||
return action.Id = createGuid(), useractionrepository.set(action.Id, action)
|
||||
}
|
||||
|
||||
function getUserActions(serverId) {
|
||||
return useractionrepository.getByServerId(serverId)
|
||||
}
|
||||
|
||||
function deleteUserAction(action) {
|
||||
return useractionrepository.remove(action.Id)
|
||||
}
|
||||
|
||||
function deleteUserActions(actions) {
|
||||
var results = [];
|
||||
return actions.forEach(function(action) {
|
||||
results.push(deleteUserAction(action))
|
||||
}), Promise.all(results)
|
||||
}
|
||||
|
||||
function getServerItems(serverId) {
|
||||
return console.debug("localassetmanager: begin getServerItems"), itemrepository.getAll(serverId)
|
||||
}
|
||||
|
||||
function getItemsFromIds(serverId, ids) {
|
||||
var actions = ids.map(function(id) {
|
||||
var strippedId = stripStart(id, "local:");
|
||||
return getLocalItem(serverId, strippedId)
|
||||
});
|
||||
return Promise.all(actions).then(function(items) {
|
||||
var libItems = items.map(function(locItem) {
|
||||
return locItem.Item
|
||||
});
|
||||
return Promise.resolve(libItems)
|
||||
})
|
||||
}
|
||||
|
||||
function getViews(serverId, userId) {
|
||||
return itemrepository.getServerItemTypes(serverId, userId).then(function(types) {
|
||||
var item, list = [];
|
||||
return types.indexOf("Audio") > -1 && (item = {
|
||||
Name: "Music",
|
||||
ServerId: serverId,
|
||||
Id: "localview:MusicView",
|
||||
Type: "MusicView",
|
||||
CollectionType: "music",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), types.indexOf("Photo") > -1 && (item = {
|
||||
Name: "Photos",
|
||||
ServerId: serverId,
|
||||
Id: "localview:PhotosView",
|
||||
Type: "PhotosView",
|
||||
CollectionType: "photos",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), types.indexOf("Episode") > -1 && (item = {
|
||||
Name: "TV",
|
||||
ServerId: serverId,
|
||||
Id: "localview:TVView",
|
||||
Type: "TVView",
|
||||
CollectionType: "tvshows",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), types.indexOf("Movie") > -1 && (item = {
|
||||
Name: "Movies",
|
||||
ServerId: serverId,
|
||||
Id: "localview:MoviesView",
|
||||
Type: "MoviesView",
|
||||
CollectionType: "movies",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), types.indexOf("Video") > -1 && (item = {
|
||||
Name: "Videos",
|
||||
ServerId: serverId,
|
||||
Id: "localview:VideosView",
|
||||
Type: "VideosView",
|
||||
CollectionType: "videos",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), types.indexOf("MusicVideo") > -1 && (item = {
|
||||
Name: "Music Videos",
|
||||
ServerId: serverId,
|
||||
Id: "localview:MusicVideosView",
|
||||
Type: "MusicVideosView",
|
||||
CollectionType: "videos",
|
||||
IsFolder: !0
|
||||
}, list.push(item)), Promise.resolve(list)
|
||||
})
|
||||
}
|
||||
|
||||
function updateFiltersForTopLevelView(parentId, mediaTypes, includeItemTypes, query) {
|
||||
switch (parentId) {
|
||||
case "MusicView":
|
||||
return query.Recursive ? includeItemTypes.push("Audio") : includeItemTypes.push("MusicAlbum"), !0;
|
||||
case "PhotosView":
|
||||
return query.Recursive ? includeItemTypes.push("Photo") : includeItemTypes.push("PhotoAlbum"), !0;
|
||||
case "TVView":
|
||||
return query.Recursive ? includeItemTypes.push("Episode") : includeItemTypes.push("Series"), !0;
|
||||
case "VideosView":
|
||||
return query.Recursive, includeItemTypes.push("Video"), !0;
|
||||
case "MoviesView":
|
||||
return query.Recursive, includeItemTypes.push("Movie"), !0;
|
||||
case "MusicVideosView":
|
||||
return query.Recursive, includeItemTypes.push("MusicVideo"), !0
|
||||
}
|
||||
return !1
|
||||
}
|
||||
|
||||
function normalizeId(id) {
|
||||
return id ? (id = stripStart(id, "localview:"), id = stripStart(id, "local:")) : null
|
||||
}
|
||||
|
||||
function normalizeIdList(val) {
|
||||
return val ? val.split(",").map(normalizeId) : []
|
||||
}
|
||||
|
||||
function shuffle(array) {
|
||||
for (var temporaryValue, randomIndex, currentIndex = array.length; 0 !== currentIndex;) randomIndex = Math.floor(Math.random() * currentIndex), currentIndex -= 1, temporaryValue = array[currentIndex], array[currentIndex] = array[randomIndex], array[randomIndex] = temporaryValue;
|
||||
return array
|
||||
}
|
||||
|
||||
function sortItems(items, query) {
|
||||
if (!query.SortBy || 0 === query.SortBy.length) return items;
|
||||
if ("Random" === query.SortBy) return shuffle(items);
|
||||
var sortSpec = getSortSpec(query);
|
||||
return items.sort(function(a, b) {
|
||||
for (var i = 0; i < sortSpec.length; i++) {
|
||||
var result = compareValues(a, b, sortSpec[i].Field, sortSpec[i].OrderDescending);
|
||||
if (0 !== result) return result
|
||||
}
|
||||
return 0
|
||||
}), items
|
||||
}
|
||||
|
||||
function compareValues(a, b, field, orderDesc) {
|
||||
if (!a.hasOwnProperty(field) || !b.hasOwnProperty(field)) return 0;
|
||||
var valA = a[field],
|
||||
valB = b[field],
|
||||
result = 0;
|
||||
return "string" == typeof valA || "string" == typeof valB ? (valA = valA || "", valB = valB || "", result = valA.toLowerCase().localeCompare(valB.toLowerCase())) : valA > valB ? result = 1 : valA < valB && (result = -1), orderDesc && (result *= -1), result
|
||||
}
|
||||
|
||||
function getSortSpec(query) {
|
||||
for (var sortFields = (query.SortBy || "").split(","), sortOrders = (query.SortOrder || "").split(","), sortSpec = [], i = 0; i < sortFields.length; i++) {
|
||||
var orderDesc = !1;
|
||||
i < sortOrders.length && -1 !== sortOrders[i].toLowerCase().indexOf("desc") && (orderDesc = !0), sortSpec.push({
|
||||
Field: sortFields[i],
|
||||
OrderDescending: orderDesc
|
||||
})
|
||||
}
|
||||
return sortSpec
|
||||
}
|
||||
|
||||
function getViewItems(serverId, userId, options) {
|
||||
var searchParentId = options.ParentId;
|
||||
searchParentId = normalizeId(searchParentId);
|
||||
var seasonId = normalizeId(options.SeasonId || options.seasonId),
|
||||
seriesId = normalizeId(options.SeriesId || options.seriesId),
|
||||
albumIds = normalizeIdList(options.AlbumIds || options.albumIds),
|
||||
includeItemTypes = options.IncludeItemTypes ? options.IncludeItemTypes.split(",") : [],
|
||||
filters = options.Filters ? options.Filters.split(",") : [],
|
||||
mediaTypes = options.MediaTypes ? options.MediaTypes.split(",") : [];
|
||||
return updateFiltersForTopLevelView(searchParentId, mediaTypes, includeItemTypes, options) && (searchParentId = null), getServerItems(serverId).then(function(items) {
|
||||
var itemsMap = new Map,
|
||||
subtreeIdSet = new Set;
|
||||
if (items.forEach(function(item) {
|
||||
item.Item.LocalChildren = [], itemsMap.set(item.Item.Id, item.Item)
|
||||
}), itemsMap.forEach(function(item, ignored, ignored2) {
|
||||
if (item.ParentId && itemsMap.has(item.ParentId)) {
|
||||
itemsMap.get(item.ParentId).LocalChildren.push(item)
|
||||
}
|
||||
}), options.Recursive && searchParentId && itemsMap.has(searchParentId)) {
|
||||
var addSubtreeIds = function(recurseItem) {
|
||||
subtreeIdSet.has(recurseItem.Id) || subtreeIdSet.add(recurseItem.Id), recurseItem.LocalChildren.forEach(function(childItem) {
|
||||
addSubtreeIds(childItem)
|
||||
})
|
||||
},
|
||||
searchParentItem = itemsMap.get(searchParentId);
|
||||
addSubtreeIds(searchParentItem)
|
||||
}
|
||||
var resultItems = items.filter(function(item) {
|
||||
return (!item.SyncStatus || "synced" === item.SyncStatus) && ((!mediaTypes.length || -1 !== mediaTypes.indexOf(item.Item.MediaType || "")) && ((!seriesId || item.Item.SeriesId === seriesId) && ((!seasonId || item.Item.SeasonId === seasonId) && ((!albumIds.length || -1 !== albumIds.indexOf(item.Item.AlbumId || "")) && ((!item.Item.IsFolder || -1 === filters.indexOf("IsNotFolder")) && (!(!item.Item.IsFolder && -1 !== filters.indexOf("IsFolder")) && ((!includeItemTypes.length || -1 !== includeItemTypes.indexOf(item.Item.Type || "")) && (!searchParentId || (options.Recursive ? subtreeIdSet.has(item.Item.Id) : item.Item.ParentId === searchParentId)))))))))
|
||||
}).map(function(item2) {
|
||||
return item2.Item
|
||||
});
|
||||
return resultItems = sortItems(resultItems, options), options.Limit && (resultItems = resultItems.slice(0, options.Limit)), Promise.resolve(resultItems)
|
||||
})
|
||||
}
|
||||
|
||||
function removeObsoleteContainerItems(serverId) {
|
||||
return getServerItems(serverId).then(function(items) {
|
||||
var seriesItems = items.filter(function(item) {
|
||||
return "series" === (item.Item.Type || "").toLowerCase()
|
||||
}),
|
||||
seasonItems = items.filter(function(item) {
|
||||
return "season" === (item.Item.Type || "").toLowerCase()
|
||||
}),
|
||||
albumItems = items.filter(function(item) {
|
||||
var type = (item.Item.Type || "").toLowerCase();
|
||||
return "musicalbum" === type || "photoalbum" === type
|
||||
}),
|
||||
requiredSeriesIds = items.filter(function(item) {
|
||||
return "episode" === (item.Item.Type || "").toLowerCase()
|
||||
}).map(function(item2) {
|
||||
return item2.Item.SeriesId
|
||||
}).filter(filterDistinct),
|
||||
requiredSeasonIds = items.filter(function(item) {
|
||||
return "episode" === (item.Item.Type || "").toLowerCase()
|
||||
}).map(function(item2) {
|
||||
return item2.Item.SeasonId
|
||||
}).filter(filterDistinct),
|
||||
requiredAlbumIds = items.filter(function(item) {
|
||||
var type = (item.Item.Type || "").toLowerCase();
|
||||
return "audio" === type || "photo" === type
|
||||
}).map(function(item2) {
|
||||
return item2.Item.AlbumId
|
||||
}).filter(filterDistinct),
|
||||
obsoleteItems = [];
|
||||
seriesItems.forEach(function(item) {
|
||||
requiredSeriesIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item)
|
||||
}), seasonItems.forEach(function(item) {
|
||||
requiredSeasonIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item)
|
||||
}), albumItems.forEach(function(item) {
|
||||
requiredAlbumIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item)
|
||||
});
|
||||
var p = Promise.resolve();
|
||||
return obsoleteItems.forEach(function(item) {
|
||||
p = p.then(function() {
|
||||
return itemrepository.remove(item.ServerId, item.Id)
|
||||
})
|
||||
}), p
|
||||
})
|
||||
}
|
||||
|
||||
function removeLocalItem(localItem) {
|
||||
return itemrepository.get(localItem.ServerId, localItem.Id).then(function(item) {
|
||||
var onFileDeletedSuccessOrFail = function() {
|
||||
return itemrepository.remove(localItem.ServerId, localItem.Id)
|
||||
},
|
||||
p = Promise.resolve();
|
||||
return item.LocalPath && (p = p.then(function() {
|
||||
return filerepository.deleteFile(item.LocalPath)
|
||||
})), item && item.Item && item.Item.MediaSources && item.Item.MediaSources.forEach(function(mediaSource) {
|
||||
mediaSource.MediaStreams && mediaSource.MediaStreams.length > 0 && mediaSource.MediaStreams.forEach(function(mediaStream) {
|
||||
mediaStream.Path && (p = p.then(function() {
|
||||
return filerepository.deleteFile(mediaStream.Path)
|
||||
}))
|
||||
})
|
||||
}), p.then(onFileDeletedSuccessOrFail, onFileDeletedSuccessOrFail)
|
||||
}, function(item) {
|
||||
return Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function addOrUpdateLocalItem(localItem) {
|
||||
return itemrepository.set(localItem.ServerId, localItem.Id, localItem)
|
||||
}
|
||||
|
||||
function getSubtitleSaveFileName(localItem, mediaPath, language, isForced, format) {
|
||||
var name = getNameWithoutExtension(mediaPath);
|
||||
name = filerepository.getValidFileName(name), language && (name += "." + language.toLowerCase()), isForced && (name += ".foreign"), name = name + "." + format.toLowerCase();
|
||||
var mediaFolder = filerepository.getParentPath(localItem.LocalPath);
|
||||
return filerepository.combinePath(mediaFolder, name)
|
||||
}
|
||||
|
||||
function getItemFileSize(path) {
|
||||
return filerepository.getItemFileSize(path)
|
||||
}
|
||||
|
||||
function getNameWithoutExtension(path) {
|
||||
var fileName = path,
|
||||
pos = fileName.lastIndexOf(".");
|
||||
return pos > 0 && (fileName = fileName.substring(0, pos)), fileName
|
||||
}
|
||||
|
||||
function downloadFile(url, localItem) {
|
||||
var imageUrl = getImageUrl(localItem.Item.ServerId, localItem.Item.Id, {
|
||||
type: "Primary",
|
||||
index: 0
|
||||
});
|
||||
return transfermanager.downloadFile(url, localItem, imageUrl)
|
||||
}
|
||||
|
||||
function downloadSubtitles(url, fileName) {
|
||||
return transfermanager.downloadSubtitles(url, fileName)
|
||||
}
|
||||
|
||||
function getImageUrl(serverId, itemId, imageOptions) {
|
||||
var imageType = imageOptions.type,
|
||||
index = imageOptions.index,
|
||||
pathArray = getImagePath(serverId, itemId, imageType, index);
|
||||
return filerepository.getImageUrl(pathArray)
|
||||
}
|
||||
|
||||
function hasImage(serverId, itemId, imageType, index) {
|
||||
var pathArray = getImagePath(serverId, itemId, imageType, index),
|
||||
localFilePath = filerepository.getFullMetadataPath(pathArray);
|
||||
return filerepository.fileExists(localFilePath).then(function(exists) {
|
||||
return Promise.resolve(exists)
|
||||
}, function(err) {
|
||||
return Promise.resolve(!1)
|
||||
})
|
||||
}
|
||||
|
||||
function fileExists(localFilePath) {
|
||||
return filerepository.fileExists(localFilePath)
|
||||
}
|
||||
|
||||
function downloadImage(localItem, url, serverId, itemId, imageType, index) {
|
||||
var localPathParts = getImagePath(serverId, itemId, imageType, index);
|
||||
return transfermanager.downloadImage(url, localPathParts)
|
||||
}
|
||||
|
||||
function isDownloadFileInQueue(path) {
|
||||
return transfermanager.isDownloadFileInQueue(path)
|
||||
}
|
||||
|
||||
function getDownloadItemCount() {
|
||||
return transfermanager.getDownloadItemCount()
|
||||
}
|
||||
|
||||
function getDirectoryPath(item) {
|
||||
var parts = [],
|
||||
itemtype = item.Type.toLowerCase(),
|
||||
mediaType = (item.MediaType || "").toLowerCase();
|
||||
"episode" === itemtype || "series" === itemtype || "season" === itemtype ? parts.push("TV") : "video" === mediaType ? parts.push("Videos") : "audio" === itemtype || "musicalbum" === itemtype || "musicartist" === itemtype ? parts.push("Music") : "photo" === itemtype || "photoalbum" === itemtype ? parts.push("Photos") : null;
|
||||
var albumArtist = item.AlbumArtist;
|
||||
albumArtist && parts.push(albumArtist);
|
||||
var seriesName = item.SeriesName;
|
||||
seriesName && parts.push(seriesName);
|
||||
var seasonName = item.SeasonName;
|
||||
seasonName && parts.push(seasonName), item.Album && parts.push(item.Album), ("video" === mediaType && "episode" !== itemtype || item.IsFolder) && parts.push(item.Name);
|
||||
for (var finalParts = [], i = 0; i < parts.length; i++) finalParts.push(filerepository.getValidFileName(parts[i]));
|
||||
return finalParts
|
||||
}
|
||||
|
||||
function getImagePath(serverId, itemId, imageType, index) {
|
||||
var parts = [];
|
||||
parts.push("images"), index = index || 0, parts.push(itemId + "_" + imageType + "_" + index.toString());
|
||||
for (var finalParts = [], i = 0; i < parts.length; i++) finalParts.push(parts[i]);
|
||||
return finalParts
|
||||
}
|
||||
|
||||
function getLocalFileName(item, originalFileName) {
|
||||
var filename = originalFileName || item.Name;
|
||||
return filerepository.getValidFileName(filename)
|
||||
}
|
||||
|
||||
function resyncTransfers() {
|
||||
return transfermanager.resyncTransfers()
|
||||
}
|
||||
|
||||
function createGuid() {
|
||||
var d = (new Date).getTime();
|
||||
return window.performance && "function" == typeof window.performance.now && (d += performance.now()), "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
||||
var r = (d + 16 * Math.random()) % 16 | 0;
|
||||
return d = Math.floor(d / 16), ("x" === c ? r : 3 & r | 8).toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
function startsWith(str, find) {
|
||||
return !!(str && find && str.length > find.length && 0 === str.indexOf(find))
|
||||
}
|
||||
|
||||
function stripStart(str, find) {
|
||||
return startsWith(str, find) ? str.substr(find.length) : str
|
||||
}
|
||||
|
||||
function filterDistinct(value, index, self) {
|
||||
return self.indexOf(value) === index
|
||||
}
|
||||
|
||||
function enableBackgroundCompletion() {
|
||||
return transfermanager.enableBackgroundCompletion
|
||||
}
|
||||
return {
|
||||
getLocalItem: getLocalItem,
|
||||
getDirectoryPath: getDirectoryPath,
|
||||
getLocalFileName: getLocalFileName,
|
||||
recordUserAction: recordUserAction,
|
||||
getUserActions: getUserActions,
|
||||
deleteUserAction: deleteUserAction,
|
||||
deleteUserActions: deleteUserActions,
|
||||
removeLocalItem: removeLocalItem,
|
||||
addOrUpdateLocalItem: addOrUpdateLocalItem,
|
||||
downloadFile: downloadFile,
|
||||
downloadSubtitles: downloadSubtitles,
|
||||
hasImage: hasImage,
|
||||
downloadImage: downloadImage,
|
||||
getImageUrl: getImageUrl,
|
||||
getSubtitleSaveFileName: getSubtitleSaveFileName,
|
||||
getServerItems: getServerItems,
|
||||
getItemFileSize: getItemFileSize,
|
||||
isDownloadFileInQueue: isDownloadFileInQueue,
|
||||
getDownloadItemCount: getDownloadItemCount,
|
||||
getViews: getViews,
|
||||
getViewItems: getViewItems,
|
||||
resyncTransfers: resyncTransfers,
|
||||
getItemsFromIds: getItemsFromIds,
|
||||
removeObsoleteContainerItems: removeObsoleteContainerItems,
|
||||
fileExists: fileExists,
|
||||
enableBackgroundCompletion: enableBackgroundCompletion
|
||||
}
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"main": "apiclient.js"
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function getValidFileName(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
function getFullLocalPath(pathArray) {
|
||||
return pathArray.join("/")
|
||||
}
|
||||
|
||||
function getPathFromArray(pathArray) {
|
||||
return pathArray.join("/")
|
||||
}
|
||||
|
||||
function deleteFile(path) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function deleteDirectory(path) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fileExists(path) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function getItemFileSize(path) {
|
||||
return Promise.resolve(0)
|
||||
}
|
||||
|
||||
function getImageUrl(pathParts) {
|
||||
return pathParts.join("/")
|
||||
}
|
||||
return {
|
||||
getValidFileName: getValidFileName,
|
||||
getFullLocalPath: getFullLocalPath,
|
||||
getPathFromArray: getPathFromArray,
|
||||
deleteFile: deleteFile,
|
||||
deleteDirectory: deleteDirectory,
|
||||
fileExists: fileExists,
|
||||
getItemFileSize: getItemFileSize,
|
||||
getImageUrl: getImageUrl
|
||||
}
|
||||
});
|
@ -1,123 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function ServerDatabase(dbName, readyCallback) {
|
||||
var request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = function(event) {}, request.onupgradeneeded = function(event) {
|
||||
var db = event.target.result;
|
||||
db.createObjectStore(dbName).transaction.oncomplete = function(event) {
|
||||
readyCallback(db)
|
||||
}
|
||||
}, request.onsuccess = function(event) {
|
||||
var db = event.target.result;
|
||||
readyCallback(db)
|
||||
}
|
||||
}
|
||||
|
||||
function getDbName(serverId) {
|
||||
return "items_" + serverId
|
||||
}
|
||||
|
||||
function getDb(serverId, callback) {
|
||||
var dbName = getDbName(serverId),
|
||||
db = databases[dbName];
|
||||
if (db) return void callback(db);
|
||||
new ServerDatabase(dbName, function(db) {
|
||||
databases[dbName] = db, callback(db)
|
||||
})
|
||||
}
|
||||
|
||||
function getServerItemTypes(serverId, userId) {
|
||||
return getAll(serverId, userId).then(function(all) {
|
||||
return all.map(function(item2) {
|
||||
return item2.Item.Type || ""
|
||||
}).filter(filterDistinct)
|
||||
})
|
||||
}
|
||||
|
||||
function getAll(serverId, userId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(serverId, function(db) {
|
||||
var request, storeName = getDbName(serverId),
|
||||
transaction = db.transaction([storeName], "readonly"),
|
||||
objectStore = transaction.objectStore(storeName);
|
||||
if ("getAll" in objectStore) request = objectStore.getAll(null, 1e4), request.onsuccess = function(event) {
|
||||
resolve(event.target.result)
|
||||
};
|
||||
else {
|
||||
var results = [];
|
||||
request = objectStore.openCursor(), request.onsuccess = function(event) {
|
||||
var cursor = event.target.result;
|
||||
cursor ? (results.push(cursor.value), cursor.continue()) : resolve(results)
|
||||
}
|
||||
}
|
||||
request.onerror = reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function get(serverId, key) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(serverId, function(db) {
|
||||
var storeName = getDbName(serverId),
|
||||
transaction = db.transaction([storeName], "readonly"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.get(key);
|
||||
request.onerror = reject, request.onsuccess = function(event) {
|
||||
resolve(request.result)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function set(serverId, key, val) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(serverId, function(db) {
|
||||
var storeName = getDbName(serverId),
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.put(val, key);
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function remove(serverId, key) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(serverId, function(db) {
|
||||
var storeName = getDbName(serverId),
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.delete(key);
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function clear(serverId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(serverId, function(db) {
|
||||
var storeName = getDbName(serverId),
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.clear();
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function filterDistinct(value, index, self) {
|
||||
return self.indexOf(value) === index
|
||||
}
|
||||
var indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB,
|
||||
dbVersion = (self.IDBTransaction || self.webkitIDBTransaction || self.msIDBTransaction, self.IDBKeyRange || self.webkitIDBKeyRange || self.msIDBKeyRange, 1),
|
||||
databases = {};
|
||||
return {
|
||||
get: get,
|
||||
set: set,
|
||||
remove: remove,
|
||||
clear: clear,
|
||||
getAll: getAll,
|
||||
getServerItemTypes: getServerItemTypes
|
||||
}
|
||||
});
|
@ -1,17 +0,0 @@
|
||||
define(["connectionManager"], function(connectionManager) {
|
||||
"use strict";
|
||||
var isSyncing;
|
||||
return {
|
||||
sync: function(options) {
|
||||
return console.debug("localSync.sync starting..."), isSyncing ? Promise.resolve() : (isSyncing = !0, new Promise(function(resolve, reject) {
|
||||
require(["multiserversync", "appSettings"], function(MultiServerSync, appSettings) {
|
||||
options = options || {}, options.cameraUploadServers = appSettings.cameraUploadServers(), (new MultiServerSync).sync(connectionManager, options).then(function() {
|
||||
isSyncing = null, resolve()
|
||||
}, function(err) {
|
||||
isSyncing = null, reject(err)
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
});
|
@ -1,370 +0,0 @@
|
||||
define(["localassetmanager"], function(localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
function processDownloadStatus(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: begin processDownloadStatus"), localassetmanager.resyncTransfers().then(function() {
|
||||
return localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
console.debug("mediasync: begin processDownloadStatus getServerItems completed");
|
||||
var p = Promise.resolve(),
|
||||
cnt = 0;
|
||||
return items.filter(function(item) {
|
||||
return "transferring" === item.SyncStatus || "queued" === item.SyncStatus
|
||||
}).forEach(function(item) {
|
||||
p = p.then(function() {
|
||||
return reportTransfer(apiClient, item)
|
||||
}), cnt++
|
||||
}), p.then(function() {
|
||||
console.debug("mediasync: exit processDownloadStatus");
|
||||
console.debug("items reported: " + cnt.toString());
|
||||
return Promise.resolve();
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function reportTransfer(apiClient, item) {
|
||||
return localassetmanager.getItemFileSize(item.LocalPath).then(function(size) {
|
||||
return size > 0 ? apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function() {
|
||||
return item.SyncStatus = "synced", console.debug("mediasync: reportSyncJobItemTransferred called for " + item.LocalPath), localassetmanager.addOrUpdateLocalItem(item)
|
||||
}, function(error) {
|
||||
return console.error("mediasync: mediasync error on reportSyncJobItemTransferred", error), item.SyncStatus = "error", localassetmanager.addOrUpdateLocalItem(item)
|
||||
}) : localassetmanager.isDownloadFileInQueue(item.LocalPath).then(function(result) {
|
||||
return result ? Promise.resolve() : (console.debug("mediasync: reportTransfer: Size is 0 and download no longer in queue. Deleting item."), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.debug("mediasync: reportTransfer: Item deleted."), Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.debug("mediasync: reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
}))
|
||||
})
|
||||
}, function(error) {
|
||||
return console.error("mediasync: reportTransfer: error on getItemFileSize. Deleting item.", error), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.debug("mediasync: reportTransfer: Item deleted."), Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.error("mediasync: reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function reportOfflineActions(apiClient, serverInfo) {
|
||||
return console.debug("mediasync: begin reportOfflineActions"), localassetmanager.getUserActions(serverInfo.Id).then(function(actions) {
|
||||
return actions.length ? apiClient.reportOfflineActions(actions).then(function() {
|
||||
return localassetmanager.deleteUserActions(actions).then(function() {
|
||||
return console.debug("mediasync: exit reportOfflineActions (actions reported and deleted.)"), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error on apiClient.reportOfflineActions: " + err.toString()), localassetmanager.deleteUserActions(actions)
|
||||
}) : (console.debug("mediasync: exit reportOfflineActions (no actions)"), Promise.resolve())
|
||||
})
|
||||
}
|
||||
|
||||
function syncData(apiClient, serverInfo) {
|
||||
return console.debug("mediasync: begin syncData"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
var completedItems = items.filter(function(item) {
|
||||
return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus)
|
||||
}),
|
||||
request = {
|
||||
TargetId: apiClient.deviceId(),
|
||||
LocalItemIds: completedItems.map(function(xitem) {
|
||||
return xitem.ItemId
|
||||
})
|
||||
};
|
||||
return apiClient.syncData(request).then(function(result) {
|
||||
return afterSyncData(apiClient, serverInfo, result).then(function() {
|
||||
return console.debug("mediasync: exit syncData"), Promise.resolve()
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error in syncData: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function afterSyncData(apiClient, serverInfo, syncDataResult) {
|
||||
console.debug("mediasync: begin afterSyncData");
|
||||
var p = Promise.resolve();
|
||||
return syncDataResult.ItemIdsToRemove && syncDataResult.ItemIdsToRemove.length > 0 && syncDataResult.ItemIdsToRemove.forEach(function(itemId) {
|
||||
p = p.then(function() {
|
||||
return removeLocalItem(itemId, serverInfo.Id)
|
||||
})
|
||||
}), p = p.then(function() {
|
||||
return removeObsoleteContainerItems(serverInfo.Id)
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit afterSyncData"), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function removeObsoleteContainerItems(serverId) {
|
||||
return console.debug("mediasync: begin removeObsoleteContainerItems"), localassetmanager.removeObsoleteContainerItems(serverId)
|
||||
}
|
||||
|
||||
function removeLocalItem(itemId, serverId) {
|
||||
return console.debug("mediasync: begin removeLocalItem"), localassetmanager.getLocalItem(serverId, itemId).then(function(item) {
|
||||
return item ? localassetmanager.removeLocalItem(item) : Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.error("mediasync: removeLocalItem: Failed: ", err2), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getNewMedia(apiClient, downloadCount) {
|
||||
return console.debug("mediasync: begin getNewMedia"), apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems) {
|
||||
console.debug("mediasync: getReadySyncItems returned " + jobItems.length + " items");
|
||||
var p = Promise.resolve(),
|
||||
currentCount = downloadCount;
|
||||
return jobItems.forEach(function(jobItem) {
|
||||
currentCount++ <= 10 && (p = p.then(function() {
|
||||
return getNewItem(jobItem, apiClient)
|
||||
}))
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit getNewMedia"), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: getReadySyncItems: Failed: ", err), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function afterMediaDownloaded(apiClient, jobItem, localItem) {
|
||||
return console.debug("mediasync: begin afterMediaDownloaded"), getImages(apiClient, jobItem, localItem).then(function() {
|
||||
var libraryItem = jobItem.Item;
|
||||
return downloadParentItems(apiClient, jobItem, libraryItem).then(function() {
|
||||
return getSubtitles(apiClient, jobItem, localItem)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function createLocalItem(libraryItem, jobItem) {
|
||||
console.debug("localassetmanager: begin createLocalItem");
|
||||
var item = {
|
||||
Item: libraryItem,
|
||||
ItemId: libraryItem.Id,
|
||||
ServerId: libraryItem.ServerId,
|
||||
Id: libraryItem.Id
|
||||
};
|
||||
return jobItem && (item.SyncJobItemId = jobItem.SyncJobItemId), console.debug("localassetmanager: end createLocalItem"), item
|
||||
}
|
||||
|
||||
function getNewItem(jobItem, apiClient) {
|
||||
console.debug("mediasync: begin getNewItem");
|
||||
var libraryItem = jobItem.Item;
|
||||
return localassetmanager.getLocalItem(libraryItem.ServerId, libraryItem.Id).then(function(existingItem) {
|
||||
if (existingItem && ("queued" === existingItem.SyncStatus || "transferring" === existingItem.SyncStatus || "synced" === existingItem.SyncStatus) && (console.debug("mediasync: getNewItem: getLocalItem found existing item"), localassetmanager.enableBackgroundCompletion())) return Promise.resolve();
|
||||
libraryItem.CanDelete = !1, libraryItem.CanDownload = !1, libraryItem.SupportsSync = !1, libraryItem.People = [], libraryItem.Chapters = [], libraryItem.Studios = [], libraryItem.SpecialFeatureCount = null, libraryItem.LocalTrailerCount = null, libraryItem.RemoteTrailers = [];
|
||||
var localItem = createLocalItem(libraryItem, jobItem);
|
||||
return localItem.SyncStatus = "queued", downloadMedia(apiClient, jobItem, localItem)
|
||||
})
|
||||
}
|
||||
|
||||
function downloadParentItems(apiClient, jobItem, libraryItem) {
|
||||
var p = Promise.resolve();
|
||||
return libraryItem.SeriesId && (p = p.then(function() {
|
||||
return downloadItem(apiClient, libraryItem.SeriesId)
|
||||
})), libraryItem.SeasonId && (p = p.then(function() {
|
||||
return downloadItem(apiClient, libraryItem.SeasonId).then(function(seasonItem) {
|
||||
return libraryItem.SeasonPrimaryImageTag = (seasonItem.Item.ImageTags || {}).Primary, Promise.resolve()
|
||||
})
|
||||
})), libraryItem.AlbumId && (p = p.then(function() {
|
||||
return downloadItem(apiClient, libraryItem.AlbumId)
|
||||
})), p
|
||||
}
|
||||
|
||||
function downloadItem(apiClient, itemId) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(downloadedItem) {
|
||||
downloadedItem.CanDelete = !1, downloadedItem.CanDownload = !1, downloadedItem.SupportsSync = !1, downloadedItem.People = [], downloadedItem.SpecialFeatureCount = null, downloadedItem.BackdropImageTags = null, downloadedItem.ParentBackdropImageTags = null, downloadedItem.ParentArtImageTag = null, downloadedItem.ParentLogoImageTag = null;
|
||||
var localItem = createLocalItem(downloadedItem, null);
|
||||
return localassetmanager.addOrUpdateLocalItem(localItem).then(function() {
|
||||
return Promise.resolve(localItem)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: downloadItem failed: " + err.toString()), Promise.resolve(null)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ensureLocalPathParts(localItem, jobItem) {
|
||||
if (!localItem.LocalPathParts) {
|
||||
var libraryItem = localItem.Item,
|
||||
parts = localassetmanager.getDirectoryPath(libraryItem);
|
||||
parts.push(localassetmanager.getLocalFileName(libraryItem, jobItem.OriginalFileName)), localItem.LocalPathParts = parts
|
||||
}
|
||||
}
|
||||
|
||||
function downloadMedia(apiClient, jobItem, localItem) {
|
||||
console.debug("mediasync: downloadMedia: start.");
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
return ensureLocalPathParts(localItem, jobItem), localassetmanager.downloadFile(url, localItem).then(function(result) {
|
||||
console.debug("mediasync: downloadMedia-downloadFile returned path: " + result.path);
|
||||
var localPath = result.path,
|
||||
libraryItem = localItem.Item;
|
||||
if (localPath && libraryItem.MediaSources)
|
||||
for (var i = 0; i < libraryItem.MediaSources.length; i++) {
|
||||
var mediaSource = libraryItem.MediaSources[i];
|
||||
mediaSource.Path = localPath, mediaSource.Protocol = "File"
|
||||
}
|
||||
return localItem.LocalPath = localPath, localItem.SyncStatus = "transferring", localassetmanager.addOrUpdateLocalItem(localItem).then(function() {
|
||||
return afterMediaDownloaded(apiClient, jobItem, localItem).then(function() {
|
||||
return result.isComplete ? (localItem.SyncStatus = "synced", reportTransfer(apiClient, localItem)) : Promise.resolve()
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: afterMediaDownloaded failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: addOrUpdateLocalItem failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: localassetmanager.downloadFile failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
function getImages(apiClient, jobItem, localItem) {
|
||||
console.debug("mediasync: begin getImages");
|
||||
var p = Promise.resolve(),
|
||||
libraryItem = localItem.Item,
|
||||
serverId = libraryItem.ServerId,
|
||||
mainImageTag = (libraryItem.ImageTags || {}).Primary;
|
||||
libraryItem.Id && mainImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.Id, mainImageTag, "Primary")
|
||||
}));
|
||||
var logoImageTag = (libraryItem.ImageTags || {}).Logo;
|
||||
libraryItem.Id && logoImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.Id, logoImageTag, "Logo")
|
||||
}));
|
||||
var artImageTag = (libraryItem.ImageTags || {}).Art;
|
||||
libraryItem.Id && artImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.Id, artImageTag, "Art")
|
||||
}));
|
||||
var bannerImageTag = (libraryItem.ImageTags || {}).Banner;
|
||||
libraryItem.Id && bannerImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.Id, bannerImageTag, "Banner")
|
||||
}));
|
||||
var thumbImageTag = (libraryItem.ImageTags || {}).Thumb;
|
||||
if (libraryItem.Id && thumbImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.Id, thumbImageTag, "Thumb")
|
||||
})), libraryItem.Id && libraryItem.BackdropImageTags)
|
||||
for (var i = 0; i < libraryItem.BackdropImageTags.length; i++);
|
||||
return libraryItem.SeriesId && libraryItem.SeriesPrimaryImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.SeriesId, libraryItem.SeriesPrimaryImageTag, "Primary")
|
||||
})), libraryItem.SeriesId && libraryItem.SeriesThumbImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.SeriesId, libraryItem.SeriesThumbImageTag, "Thumb")
|
||||
})), libraryItem.SeasonId && libraryItem.SeasonPrimaryImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.SeasonId, libraryItem.SeasonPrimaryImageTag, "Primary")
|
||||
})), libraryItem.AlbumId && libraryItem.AlbumPrimaryImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.AlbumId, libraryItem.AlbumPrimaryImageTag, "Primary")
|
||||
})), libraryItem.ParentThumbItemId && libraryItem.ParentThumbImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.ParentThumbItemId, libraryItem.ParentThumbImageTag, "Thumb")
|
||||
})), libraryItem.ParentPrimaryImageItemId && libraryItem.ParentPrimaryImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.ParentPrimaryImageItemId, libraryItem.ParentPrimaryImageTag, "Primary")
|
||||
})), p.then(function() {
|
||||
return console.debug("mediasync: finished getImages"), localassetmanager.addOrUpdateLocalItem(localItem)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error getImages: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function downloadImage(localItem, apiClient, serverId, itemId, imageTag, imageType, index) {
|
||||
return index = index || 0, localassetmanager.hasImage(serverId, itemId, imageType, index).then(function(hasImage) {
|
||||
if (hasImage) return console.debug("mediasync: downloadImage - skip existing: " + itemId + " " + imageType + "_" + index.toString()), Promise.resolve();
|
||||
var maxWidth = 400;
|
||||
"backdrop" === imageType && (maxWidth = null);
|
||||
var imageUrl = apiClient.getScaledImageUrl(itemId, {
|
||||
tag: imageTag,
|
||||
type: imageType,
|
||||
maxWidth: maxWidth,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
return console.debug("mediasync: downloadImage " + itemId + " " + imageType + "_" + index.toString()), localassetmanager.downloadImage(localItem, imageUrl, serverId, itemId, imageType, index).then(function(result) {
|
||||
return Promise.resolve(result)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error downloadImage: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error downloadImage: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getSubtitles(apiClient, jobItem, localItem) {
|
||||
if (console.debug("mediasync: begin getSubtitles"), !jobItem.Item.MediaSources.length) return console.debug("mediasync: cannot download subtitles because video has no media source info."), Promise.resolve();
|
||||
var files = jobItem.AdditionalFiles.filter(function(f) {
|
||||
return "Subtitles" === f.Type
|
||||
}),
|
||||
mediaSource = jobItem.Item.MediaSources[0],
|
||||
p = Promise.resolve();
|
||||
return files.forEach(function(file) {
|
||||
p = p.then(function() {
|
||||
return getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource)
|
||||
})
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit getSubtitles"), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
|
||||
console.debug("mediasync: begin getItemSubtitle");
|
||||
var subtitleStream = mediaSource.MediaStreams.filter(function(m) {
|
||||
return "Subtitle" === m.Type && m.Index === file.Index
|
||||
})[0];
|
||||
if (!subtitleStream) return console.debug("mediasync: cannot download subtitles because matching stream info was not found."), Promise.resolve();
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
|
||||
Name: file.Name,
|
||||
api_key: apiClient.accessToken()
|
||||
}),
|
||||
fileName = localassetmanager.getSubtitleSaveFileName(localItem, jobItem.OriginalFileName, subtitleStream.Language, subtitleStream.IsForced, subtitleStream.Codec);
|
||||
return localassetmanager.downloadSubtitles(url, fileName).then(function(subtitleResult) {
|
||||
return localItem.AdditionalFiles && localItem.AdditionalFiles.forEach(function(item) {
|
||||
item.Name === file.Name && (item.Path = subtitleResult.path)
|
||||
}), subtitleStream.Path = subtitleResult.path, subtitleStream.DeliveryMethod = "External", localassetmanager.addOrUpdateLocalItem(localItem)
|
||||
})
|
||||
}
|
||||
|
||||
function checkLocalFileExistence(apiClient, serverInfo, options) {
|
||||
return options.checkFileExistence ? (console.debug("mediasync: begin checkLocalFileExistence"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
var completedItems = items.filter(function(item) {
|
||||
return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus)
|
||||
}),
|
||||
p = Promise.resolve();
|
||||
return completedItems.forEach(function(completedItem) {
|
||||
p = p.then(function() {
|
||||
return localassetmanager.fileExists(completedItem.LocalPath).then(function(exists) {
|
||||
return exists ? Promise.resolve() : localassetmanager.removeLocalItem(completedItem).then(function() {
|
||||
return Promise.resolve()
|
||||
}, function() {
|
||||
return Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
}), p
|
||||
})) : Promise.resolve()
|
||||
}
|
||||
return function() {
|
||||
var self = this;
|
||||
"string" == typeof webWorkerBaseUrl && -1 !== webWorkerBaseUrl.indexOf("ms-appx://") ? self.sync = function(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return processDownloadStatus(apiClient, serverInfo, options).then(function() {
|
||||
return localassetmanager.getDownloadItemCount().then(function(downloadCount) {
|
||||
return !0 === options.syncCheckProgressOnly && downloadCount > 2 ? Promise.resolve() : reportOfflineActions(apiClient, serverInfo).then(function() {
|
||||
return getNewMedia(apiClient, downloadCount).then(function() {
|
||||
return syncData(apiClient, serverInfo).then(function() {
|
||||
return console.debug("mediasync: Exit sync"), Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}, function(err) {
|
||||
console.error(err.toString())
|
||||
})
|
||||
} : self.sync = function(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return syncData(apiClient, serverInfo).then(function() {
|
||||
return processDownloadStatus(apiClient, serverInfo, options).then(function() {
|
||||
return localassetmanager.getDownloadItemCount().then(function(downloadCount) {
|
||||
return !0 === options.syncCheckProgressOnly && downloadCount > 2 ? Promise.resolve() : reportOfflineActions(apiClient, serverInfo).then(function() {
|
||||
return getNewMedia(apiClient, downloadCount).then(function() {
|
||||
return syncData(apiClient, serverInfo)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}, function(err) {
|
||||
console.error(err.toString())
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
@ -1,22 +0,0 @@
|
||||
define(["serversync"], function(ServerSync) {
|
||||
"use strict";
|
||||
|
||||
function syncNext(connectionManager, servers, index, options, resolve, reject) {
|
||||
var length = servers.length;
|
||||
if (index >= length) return console.debug("MultiServerSync.sync complete"), void resolve();
|
||||
var server = servers[index];
|
||||
console.debug("Creating ServerSync to server: " + server.Id), (new ServerSync).sync(connectionManager, server, options).then(function() {
|
||||
console.debug("ServerSync succeeded to server: " + server.Id), syncNext(connectionManager, servers, index + 1, options, resolve, reject)
|
||||
}, function(err) {
|
||||
console.error("ServerSync failed to server: " + server.Id + ". " + err), syncNext(connectionManager, servers, index + 1, options, resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
function MultiServerSync() {}
|
||||
return MultiServerSync.prototype.sync = function(connectionManager, options) {
|
||||
return console.debug("MultiServerSync.sync starting..."), new Promise(function(resolve, reject) {
|
||||
var servers = connectionManager.getSavedServers();
|
||||
syncNext(connectionManager, servers, 0, options, resolve, reject)
|
||||
})
|
||||
}, MultiServerSync
|
||||
});
|
@ -1,42 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function performSync(connectionManager, server, options) {
|
||||
console.debug("ServerSync.performSync to server: " + server.Id), options = options || {};
|
||||
var cameraUploadServers = options.cameraUploadServers || [];
|
||||
console.debug("ServerSync cameraUploadServers: " + JSON.stringify(cameraUploadServers));
|
||||
var uploadPhotos = -1 !== cameraUploadServers.indexOf(server.Id);
|
||||
return console.debug("ServerSync uploadPhotos: " + uploadPhotos), (uploadPhotos ? uploadContent(connectionManager, server, options) : Promise.resolve()).then(function() {
|
||||
return syncMedia(connectionManager, server, options)
|
||||
})
|
||||
}
|
||||
|
||||
function uploadContent(connectionManager, server, options) {
|
||||
return new Promise().reject();
|
||||
}
|
||||
|
||||
function syncMedia(connectionManager, server, options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["mediasync"], function(MediaSync) {
|
||||
var apiClient = connectionManager.getApiClient(server.Id);
|
||||
(new MediaSync).sync(apiClient, server, options).then(resolve, reject)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ServerSync() {}
|
||||
return ServerSync.prototype.sync = function(connectionManager, server, options) {
|
||||
if (!server.AccessToken && !server.ExchangeToken) return console.debug("Skipping sync to server " + server.Id + " because there is no saved authentication information."), Promise.resolve();
|
||||
var connectionOptions = {
|
||||
updateDateLastAccessed: !1,
|
||||
enableWebSocket: !1,
|
||||
reportCapabilities: !1,
|
||||
enableAutomaticBitrateDetection: !1
|
||||
};
|
||||
return connectionManager.connectToServer(server, connectionOptions).then(function(result) {
|
||||
return "SignedIn" === result.State ? performSync(connectionManager, server, options) : (console.error("Unable to connect to server id: " + server.Id), Promise.reject())
|
||||
}, function(err) {
|
||||
throw console.error("Unable to connect to server id: " + server.Id), err
|
||||
})
|
||||
}, ServerSync
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function downloadFile(url, folder, localItem, imageUrl) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
function downloadSubtitles(url, folder, fileName) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
function downloadImage(url, folder, fileName) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
function resyncTransfers() {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function getDownloadItemCount() {
|
||||
return Promise.resolve(0)
|
||||
}
|
||||
return {
|
||||
downloadFile: downloadFile,
|
||||
downloadSubtitles: downloadSubtitles,
|
||||
downloadImage: downloadImage,
|
||||
resyncTransfers: resyncTransfers,
|
||||
getDownloadItemCount: getDownloadItemCount
|
||||
}
|
||||
});
|
@ -1,108 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function getDb(callback) {
|
||||
var db = databaseInstance;
|
||||
if (db) return void callback(db);
|
||||
var request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = function(event) {}, request.onupgradeneeded = function(event) {
|
||||
var db = event.target.result;
|
||||
db.createObjectStore(dbName).transaction.oncomplete = function(event) {
|
||||
callback(db)
|
||||
}
|
||||
}, request.onsuccess = function(event) {
|
||||
var db = event.target.result;
|
||||
callback(db)
|
||||
}
|
||||
}
|
||||
|
||||
function getByServerId(serverId) {
|
||||
return getAll().then(function(items) {
|
||||
return items.filter(function(item) {
|
||||
return item.ServerId === serverId
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(function(db) {
|
||||
var request, storeName = dbName,
|
||||
transaction = db.transaction([storeName], "readonly"),
|
||||
objectStore = transaction.objectStore(storeName);
|
||||
if ("getAll" in objectStore) request = objectStore.getAll(null, 1e4), request.onsuccess = function(event) {
|
||||
resolve(event.target.result)
|
||||
};
|
||||
else {
|
||||
var results = [];
|
||||
request = objectStore.openCursor(), request.onsuccess = function(event) {
|
||||
var cursor = event.target.result;
|
||||
cursor ? (results.push(cursor.value), cursor.continue()) : resolve(results)
|
||||
}
|
||||
}
|
||||
request.onerror = reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(function(db) {
|
||||
var storeName = dbName,
|
||||
transaction = db.transaction([storeName], "readonly"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.get(key);
|
||||
request.onerror = reject, request.onsuccess = function(event) {
|
||||
resolve(request.result)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(function(db) {
|
||||
var storeName = dbName,
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.put(val, key);
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function remove(key) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(function(db) {
|
||||
var storeName = dbName,
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.delete(key);
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function clear() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
getDb(function(db) {
|
||||
var storeName = dbName,
|
||||
transaction = db.transaction([storeName], "readwrite"),
|
||||
objectStore = transaction.objectStore(storeName),
|
||||
request = objectStore.clear();
|
||||
request.onerror = reject, request.onsuccess = resolve
|
||||
})
|
||||
})
|
||||
}
|
||||
var databaseInstance, indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB,
|
||||
dbName = (self.IDBTransaction || self.webkitIDBTransaction || self.msIDBTransaction, self.IDBKeyRange || self.webkitIDBKeyRange || self.msIDBKeyRange, "useractions"),
|
||||
dbVersion = 1;
|
||||
return {
|
||||
get: get,
|
||||
set: set,
|
||||
remove: remove,
|
||||
clear: clear,
|
||||
getAll: getAll,
|
||||
getByServerId: getByServerId
|
||||
}
|
||||
});
|
@ -912,12 +912,16 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||
renderHeader();
|
||||
|
||||
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
||||
var currentApiClient = connectionManager.getApiClient(user.ServerId);
|
||||
|
||||
currentDrawerType = null;
|
||||
currentUser = {
|
||||
localUser: user
|
||||
};
|
||||
|
||||
loadNavDrawer();
|
||||
connectionManager.user(connectionManager.getApiClient(user.ServerId)).then(function (user) {
|
||||
|
||||
connectionManager.user(currentApiClient).then(function (user) {
|
||||
currentUser = user;
|
||||
updateUserInHeader(user);
|
||||
});
|
||||
|
@ -378,8 +378,6 @@ var AppInfo = {};
|
||||
define('lazyLoader', [componentsPath + '/lazyloader/lazyloader-intersectionobserver'], returnFirstDependency);
|
||||
define('shell', [componentsPath + '/shell'], returnFirstDependency);
|
||||
|
||||
define('apiclient', [bowerPath + '/apiclient/apiclient'], returnFirstDependency);
|
||||
|
||||
if ('registerElement' in document) {
|
||||
define('registerElement', []);
|
||||
} else if (browser.msie) {
|
||||
@ -401,13 +399,8 @@ var AppInfo = {};
|
||||
define('loading', [componentsPath + '/loading/loading'], returnFirstDependency);
|
||||
define('multi-download', [componentsPath + '/multidownload'], returnFirstDependency);
|
||||
define('fileDownloader', [componentsPath + '/filedownloader'], returnFirstDependency);
|
||||
define('localassetmanager', [bowerPath + '/apiclient/localassetmanager'], returnFirstDependency);
|
||||
|
||||
define('castSenderApiLoader', [componentsPath + '/castSenderApi'], returnFirstDependency);
|
||||
|
||||
define('transfermanager', [bowerPath + '/apiclient/sync/transfermanager'], returnFirstDependency);
|
||||
define('filerepository', [bowerPath + '/apiclient/sync/filerepository'], returnFirstDependency);
|
||||
define('localsync', [bowerPath + '/apiclient/sync/localsync'], returnFirstDependency);
|
||||
}
|
||||
|
||||
function init() {
|
||||
@ -696,7 +689,12 @@ var AppInfo = {};
|
||||
'intersection-observer',
|
||||
'classlist-polyfill',
|
||||
'screenfull',
|
||||
'headroom'
|
||||
'headroom',
|
||||
'apiclient',
|
||||
'events',
|
||||
'credentialprovider',
|
||||
'connectionManagerFactory',
|
||||
'appStorage'
|
||||
]
|
||||
},
|
||||
urlArgs: urlArgs,
|
||||
@ -743,17 +741,6 @@ var AppInfo = {};
|
||||
define('appFooter', [componentsPath + '/appfooter/appfooter'], returnFirstDependency);
|
||||
define('appFooter-shared', ['appFooter'], createSharedAppFooter);
|
||||
|
||||
// TODO pull apiclient out of this repository
|
||||
define('events', [bowerPath + '/apiclient/events'], returnFirstDependency);
|
||||
define('credentialprovider', [bowerPath + '/apiclient/credentialprovider'], returnFirstDependency);
|
||||
define('connectionManagerFactory', [bowerPath + '/apiclient/connectionmanager'], returnFirstDependency);
|
||||
define('appStorage', [bowerPath + '/apiclient/appStorage'], returnFirstDependency);
|
||||
define('serversync', [bowerPath + '/apiclient/sync/serversync'], returnFirstDependency);
|
||||
define('multiserversync', [bowerPath + '/apiclient/sync/multiserversync'], returnFirstDependency);
|
||||
define('mediasync', [bowerPath + '/apiclient/sync/mediasync'], returnFirstDependency);
|
||||
define('itemrepository', [bowerPath + '/apiclient/sync/itemrepository'], returnFirstDependency);
|
||||
define('useractionrepository', [bowerPath + '/apiclient/sync/useractionrepository'], returnFirstDependency);
|
||||
|
||||
// TODO remove these libraries
|
||||
// all of these have been modified so we need to fix that first
|
||||
define('scroller', [bowerPath + '/scroller'], returnFirstDependency);
|
||||
|
@ -11,7 +11,7 @@ module.exports = merge(common, {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
libraryTarget: 'amd-require'
|
||||
},
|
||||
devtool: '#inline-source-map',
|
||||
devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user