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',
|
'Uint32Array',
|
||||||
'Float32Array',
|
'Float32Array',
|
||||||
'Float64Array',
|
'Float64Array',
|
||||||
'Reflect'
|
'Reflect',
|
||||||
|
// Temporary while eslint-compat-plugin is buggy
|
||||||
|
'document.querySelector'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
"hls.js": "^0.13.1",
|
"hls.js": "^0.13.1",
|
||||||
"howler": "^2.1.3",
|
"howler": "^2.1.3",
|
||||||
"intersection-observer": "^0.10.0",
|
"intersection-observer": "^0.10.0",
|
||||||
|
"jellyfin-apiclient": "^1.1.1",
|
||||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||||
"jquery": "^3.5.0",
|
"jquery": "^3.5.0",
|
||||||
"jstree": "^3.3.7",
|
"jstree": "^3.3.7",
|
||||||
@ -91,9 +92,9 @@
|
|||||||
"src/components/autoFocuser.js",
|
"src/components/autoFocuser.js",
|
||||||
"src/components/cardbuilder/cardBuilder.js",
|
"src/components/cardbuilder/cardBuilder.js",
|
||||||
"src/components/filedownloader.js",
|
"src/components/filedownloader.js",
|
||||||
"src/components/playback/mediasession.js",
|
|
||||||
"src/components/images/imageLoader.js",
|
"src/components/images/imageLoader.js",
|
||||||
"src/components/lazyloader/lazyloader-intersectionobserver.js",
|
"src/components/lazyloader/lazyloader-intersectionobserver.js",
|
||||||
|
"src/components/playback/mediasession.js",
|
||||||
"src/components/sanatizefilename.js",
|
"src/components/sanatizefilename.js",
|
||||||
"src/components/scrollManager.js",
|
"src/components/scrollManager.js",
|
||||||
"src/scripts/dfnshelper.js",
|
"src/scripts/dfnshelper.js",
|
||||||
|
@ -108,6 +108,7 @@ _define('page', function() {
|
|||||||
return page;
|
return page;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// core-js
|
||||||
var polyfill = require('@babel/polyfill/dist/polyfill');
|
var polyfill = require('@babel/polyfill/dist/polyfill');
|
||||||
_define('polyfill', function () {
|
_define('polyfill', function () {
|
||||||
return polyfill;
|
return polyfill;
|
||||||
@ -152,3 +153,26 @@ var headroom = require('headroom.js/dist/headroom');
|
|||||||
_define('headroom', function () {
|
_define('headroom', function () {
|
||||||
return headroom;
|
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();
|
var now = Date.now();
|
||||||
|
|
||||||
if (window.performance && window.performance.now) {
|
if (window.performance && window.performance.now) {
|
||||||
now = performance.now();
|
now = performance.now(); // eslint-disable-line compat/compat
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) {
|
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();
|
renderHeader();
|
||||||
|
|
||||||
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
||||||
|
var currentApiClient = connectionManager.getApiClient(user.ServerId);
|
||||||
|
|
||||||
currentDrawerType = null;
|
currentDrawerType = null;
|
||||||
currentUser = {
|
currentUser = {
|
||||||
localUser: user
|
localUser: user
|
||||||
};
|
};
|
||||||
|
|
||||||
loadNavDrawer();
|
loadNavDrawer();
|
||||||
connectionManager.user(connectionManager.getApiClient(user.ServerId)).then(function (user) {
|
|
||||||
|
connectionManager.user(currentApiClient).then(function (user) {
|
||||||
currentUser = user;
|
currentUser = user;
|
||||||
updateUserInHeader(user);
|
updateUserInHeader(user);
|
||||||
});
|
});
|
||||||
|
@ -378,8 +378,6 @@ var AppInfo = {};
|
|||||||
define('lazyLoader', [componentsPath + '/lazyloader/lazyloader-intersectionobserver'], returnFirstDependency);
|
define('lazyLoader', [componentsPath + '/lazyloader/lazyloader-intersectionobserver'], returnFirstDependency);
|
||||||
define('shell', [componentsPath + '/shell'], returnFirstDependency);
|
define('shell', [componentsPath + '/shell'], returnFirstDependency);
|
||||||
|
|
||||||
define('apiclient', [bowerPath + '/apiclient/apiclient'], returnFirstDependency);
|
|
||||||
|
|
||||||
if ('registerElement' in document) {
|
if ('registerElement' in document) {
|
||||||
define('registerElement', []);
|
define('registerElement', []);
|
||||||
} else if (browser.msie) {
|
} else if (browser.msie) {
|
||||||
@ -401,13 +399,8 @@ var AppInfo = {};
|
|||||||
define('loading', [componentsPath + '/loading/loading'], returnFirstDependency);
|
define('loading', [componentsPath + '/loading/loading'], returnFirstDependency);
|
||||||
define('multi-download', [componentsPath + '/multidownload'], returnFirstDependency);
|
define('multi-download', [componentsPath + '/multidownload'], returnFirstDependency);
|
||||||
define('fileDownloader', [componentsPath + '/filedownloader'], returnFirstDependency);
|
define('fileDownloader', [componentsPath + '/filedownloader'], returnFirstDependency);
|
||||||
define('localassetmanager', [bowerPath + '/apiclient/localassetmanager'], returnFirstDependency);
|
|
||||||
|
|
||||||
define('castSenderApiLoader', [componentsPath + '/castSenderApi'], 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() {
|
function init() {
|
||||||
@ -696,7 +689,12 @@ var AppInfo = {};
|
|||||||
'intersection-observer',
|
'intersection-observer',
|
||||||
'classlist-polyfill',
|
'classlist-polyfill',
|
||||||
'screenfull',
|
'screenfull',
|
||||||
'headroom'
|
'headroom',
|
||||||
|
'apiclient',
|
||||||
|
'events',
|
||||||
|
'credentialprovider',
|
||||||
|
'connectionManagerFactory',
|
||||||
|
'appStorage'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
urlArgs: urlArgs,
|
urlArgs: urlArgs,
|
||||||
@ -743,17 +741,6 @@ var AppInfo = {};
|
|||||||
define('appFooter', [componentsPath + '/appfooter/appfooter'], returnFirstDependency);
|
define('appFooter', [componentsPath + '/appfooter/appfooter'], returnFirstDependency);
|
||||||
define('appFooter-shared', ['appFooter'], createSharedAppFooter);
|
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
|
// TODO remove these libraries
|
||||||
// all of these have been modified so we need to fix that first
|
// all of these have been modified so we need to fix that first
|
||||||
define('scroller', [bowerPath + '/scroller'], returnFirstDependency);
|
define('scroller', [bowerPath + '/scroller'], returnFirstDependency);
|
||||||
|
@ -11,7 +11,7 @@ module.exports = merge(common, {
|
|||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
libraryTarget: 'amd-require'
|
libraryTarget: 'amd-require'
|
||||||
},
|
},
|
||||||
devtool: '#inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user