mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-18 03:18:19 -07:00
commit
e8446c0dfe
6
MediaBrowser.WebDashboard.nuget.targets
Normal file
6
MediaBrowser.WebDashboard.nuget.targets
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="EmitMSBuildWarning" BeforeTargets="Build">
|
||||
<Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
|
||||
</Target>
|
||||
</Project>
|
@ -1,55 +0,0 @@
|
||||
<div id="aboutPage" data-role="page" class="page type-interior">
|
||||
|
||||
<div data-role="content">
|
||||
<div class="content-primary">
|
||||
<div class="readOnlyContent">
|
||||
<h1>
|
||||
<img class="imgLogoIcon" src="css/images/logo.png" />
|
||||
</h1>
|
||||
<br />
|
||||
<br />
|
||||
<div id="appVersionNumber">${VersionNumber}</div>
|
||||
<br />
|
||||
<div class="detailSectionHeader">${HeaderCredits}</div>
|
||||
<div style="padding: 0 .5em;">
|
||||
<p>
|
||||
<a href="http://www.pismotechnic.com/pfm/" target="_blank">${PismoMessage}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.tangiblesoftwaresolutions.com/" target="_blank">${TangibleSoftwareMessage}</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<p>${PleaseSupportOtherProduces}</p>
|
||||
|
||||
<p>
|
||||
<a href="http://fanart.tv" target="_blank">FanArt.tv</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://musicbrainz.org" target="_blank">MusicBrainz</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.themoviedb.org" target="_blank">TheMovieDb.org</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.omdbapi.com" target="_blank">The Open Movie Database</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://thetvdb.com" target="_blank">TheTVDB.com</a>
|
||||
</p>
|
||||
</div>
|
||||
<br/>
|
||||
<p>${ProjectHasCommunity}</p>
|
||||
<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="http://emby.media/community" target="_blank">${VisitTheCommunity}</a>
|
||||
<br />
|
||||
<p>
|
||||
${CheckoutKnowledgeBase}
|
||||
</p>
|
||||
<a data-role="button" data-icon="search" data-iconpos="right" href="http://emby.media/community/index.php?/forum/23-knowledge-base/" target="_blank">${SearchKnowledgeBase}</a>
|
||||
<br />
|
||||
<p>${VisitProjectWebsiteLong}</p>
|
||||
<a data-role="button" data-icon="home" data-iconpos="right" href="http://emby.media" target="_blank">${VisitProjectWebsite}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -16,12 +16,12 @@
|
||||
},
|
||||
"devDependencies": {},
|
||||
"ignore": [],
|
||||
"version": "1.1.91",
|
||||
"_release": "1.1.91",
|
||||
"version": "1.1.105",
|
||||
"_release": "1.1.105",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.1.91",
|
||||
"commit": "f94b80f14bce6922acf1dbd749a60ad54e4abfd8"
|
||||
"tag": "1.1.105",
|
||||
"commit": "d46515271d43d1b0f7dd19bb1834cfd457fb3326"
|
||||
},
|
||||
"_source": "https://github.com/MediaBrowser/Emby.ApiClient.Javascript.git",
|
||||
"_target": "^1.1.51",
|
||||
|
@ -22,6 +22,27 @@
|
||||
var self = this;
|
||||
var webSocket;
|
||||
var serverInfo = {};
|
||||
var lastDetectedBitrate;
|
||||
var lastDetectedBitrateTime;
|
||||
|
||||
var detectTimeout;
|
||||
function redetectBitrate() {
|
||||
stopBitrateDetection();
|
||||
|
||||
if (self.accessToken() && self.enableAutomaticBitrateDetection !== false) {
|
||||
setTimeout(redetectBitrateInternal, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
function redetectBitrateInternal() {
|
||||
self.detectBitrate();
|
||||
}
|
||||
|
||||
function stopBitrateDetection() {
|
||||
if (detectTimeout) {
|
||||
clearTimeout(detectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server address.
|
||||
@ -38,9 +59,14 @@
|
||||
|
||||
serverAddress = val;
|
||||
|
||||
lastDetectedBitrate = 0;
|
||||
lastDetectedBitrateTime = 0;
|
||||
|
||||
if (changed) {
|
||||
events.trigger(this, 'serveraddresschanged');
|
||||
}
|
||||
|
||||
redetectBitrate();
|
||||
}
|
||||
|
||||
return serverAddress;
|
||||
@ -128,6 +154,7 @@
|
||||
|
||||
serverInfo.AccessToken = accessKey;
|
||||
serverInfo.UserId = userId;
|
||||
redetectBitrate();
|
||||
};
|
||||
|
||||
self.encodeName = function (name) {
|
||||
@ -239,7 +266,7 @@
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
clearTimeout(timeout);
|
||||
reject();
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -421,11 +448,14 @@
|
||||
|
||||
}, function (error) {
|
||||
|
||||
console.log("Request failed to " + request.url);
|
||||
|
||||
// http://api.jquery.com/jQuery.ajax/
|
||||
if (enableReconnection) {
|
||||
if (error) {
|
||||
console.log("Request failed to " + request.url + ' ' + error.toString());
|
||||
} else {
|
||||
console.log("Request timed out to " + request.url + ' ' + error.toString());
|
||||
}
|
||||
|
||||
// http://api.jquery.com/jQuery.ajax/
|
||||
if (!error && enableReconnection) {
|
||||
console.log("Attempting reconnection");
|
||||
|
||||
var previousServerAddress = self.serverAddress();
|
||||
@ -669,23 +699,67 @@
|
||||
});
|
||||
};
|
||||
|
||||
self.detectBitrate = function () {
|
||||
function normalizeReturnBitrate(bitrate) {
|
||||
|
||||
// First try a small amount so that we don't hang up their mobile connection
|
||||
return self.getDownloadSpeed(1000000).then(function (bitrate) {
|
||||
if (!bitrate) {
|
||||
|
||||
if (bitrate < 1000000) {
|
||||
return Math.round(bitrate * 0.8);
|
||||
} else {
|
||||
|
||||
// If that produced a fairly high speed, try again with a larger size to get a more accurate result
|
||||
return self.getDownloadSpeed(2400000).then(function (bitrate) {
|
||||
|
||||
return Math.round(bitrate * 0.8);
|
||||
});
|
||||
if (lastDetectedBitrate) {
|
||||
return lastDetectedBitrate;
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
var result = Math.round(bitrate * 0.8);
|
||||
|
||||
lastDetectedBitrate = result;
|
||||
lastDetectedBitrateTime = new Date().getTime();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function detectBitrateInternal(tests, index, currentBitrate) {
|
||||
|
||||
if (index >= tests.length) {
|
||||
|
||||
return normalizeReturnBitrate(currentBitrate);
|
||||
}
|
||||
|
||||
var test = tests[index];
|
||||
|
||||
return self.getDownloadSpeed(test.bytes).then(function (bitrate) {
|
||||
|
||||
if (bitrate < test.threshold) {
|
||||
|
||||
return normalizeReturnBitrate(bitrate);
|
||||
} else {
|
||||
return detectBitrateInternal(tests, index + 1, bitrate);
|
||||
}
|
||||
|
||||
}, function () {
|
||||
return normalizeReturnBitrate(currentBitrate);
|
||||
});
|
||||
}
|
||||
|
||||
self.detectBitrate = function () {
|
||||
|
||||
if (lastDetectedBitrate && (new Date().getTime() - (lastDetectedBitrateTime || 0)) <= 3600000) {
|
||||
return Promise.resolve(lastDetectedBitrate);
|
||||
}
|
||||
|
||||
return detectBitrateInternal([
|
||||
{
|
||||
bytes: 100000,
|
||||
threshold: 5000000
|
||||
},
|
||||
{
|
||||
bytes: 1000000,
|
||||
threshold: 50000000
|
||||
},
|
||||
{
|
||||
bytes: 3000000,
|
||||
threshold: 50000000
|
||||
}], 0);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -768,6 +842,7 @@
|
||||
|
||||
self.logout = function () {
|
||||
|
||||
stopBitrateDetection();
|
||||
self.closeWebSocket();
|
||||
|
||||
var done = function () {
|
||||
@ -2561,6 +2636,8 @@
|
||||
self.onAuthenticated(self, result);
|
||||
}
|
||||
|
||||
redetectBitrate();
|
||||
|
||||
resolve(result);
|
||||
|
||||
}, reject);
|
||||
@ -3311,6 +3388,8 @@
|
||||
throw new Error("null options");
|
||||
}
|
||||
|
||||
stopBitrateDetection();
|
||||
|
||||
var url = self.getUrl("Sessions/Playing");
|
||||
|
||||
return self.ajax({
|
||||
@ -3439,6 +3518,8 @@
|
||||
throw new Error("null options");
|
||||
}
|
||||
|
||||
redetectBitrate();
|
||||
|
||||
var url = self.getUrl("Sessions/Playing/Stopped");
|
||||
|
||||
return self.ajax({
|
||||
|
@ -6,7 +6,10 @@
|
||||
var localData;
|
||||
|
||||
function updateCache() {
|
||||
cache.put('data', new Response(JSON.stringify(localData)));
|
||||
|
||||
if (cache) {
|
||||
cache.put('data', new Response(JSON.stringify(localData)));
|
||||
}
|
||||
}
|
||||
|
||||
myStore.setItem = function (name, value) {
|
||||
@ -38,10 +41,13 @@
|
||||
|
||||
try {
|
||||
|
||||
caches.open('embydata').then(function (result) {
|
||||
cache = result;
|
||||
localData = {};
|
||||
});
|
||||
if (self.caches) {
|
||||
|
||||
caches.open('embydata').then(function (result) {
|
||||
cache = result;
|
||||
localData = {};
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('Error opening cache: ' + err);
|
||||
|
@ -216,7 +216,7 @@
|
||||
return connectUser;
|
||||
};
|
||||
|
||||
var minServerVersion = '3.0.5994';
|
||||
var minServerVersion = '3.0.7200';
|
||||
self.minServerVersion = function (val) {
|
||||
|
||||
if (val) {
|
||||
@ -447,6 +447,7 @@
|
||||
if (options.reportCapabilities !== false) {
|
||||
apiClient.reportCapabilities(capabilities);
|
||||
}
|
||||
apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
|
||||
|
||||
if (options.enableWebSocket !== false) {
|
||||
console.log('calling apiClient.ensureWebSocket');
|
||||
@ -1509,7 +1510,7 @@
|
||||
var updateDevicePromise;
|
||||
|
||||
// Cache for 3 days
|
||||
if (params.deviceId && (new Date().getTime() - (regInfo.lastValidDate || 0)) < 259200000) {
|
||||
if (params.deviceId && (new Date().getTime() - (regInfo.lastValidDate || 0)) < 604800000) {
|
||||
|
||||
console.log('getRegistrationInfo has cached info');
|
||||
|
||||
|
114
dashboard-ui/bower_components/emby-apiclient/nullassetmanager.js
vendored
Normal file
114
dashboard-ui/bower_components/emby-apiclient/nullassetmanager.js
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getLocalMediaSource(serverId, itemId) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
function saveOfflineUser(user) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function deleteOfflineUser(id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function getCameraPhotos() {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
function recordUserAction(action) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function getUserActions(serverId) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
function deleteUserAction(action) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function deleteUserActions(actions) {
|
||||
//TODO:
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function getServerItemIds(serverId) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
function removeLocalItem(localItem) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function getLocalItem(itemId, serverId) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function addOrUpdateLocalItem(localItem) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function createLocalItem(libraryItem, serverInfo, jobItem) {
|
||||
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
function downloadFile(url, localPath) {
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function downloadSubtitles(url, localItem, subtitleStreamh) {
|
||||
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
function hasImage(serverId, itemId, imageTag) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
function downloadImage(url, serverId, itemId, imageTag) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
function fileExists(path) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
function translateFilePath(path) {
|
||||
return Promise.resolve(path);
|
||||
}
|
||||
|
||||
function getLocalFilePath(path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLocalItemById(id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
getLocalItem: getLocalItem,
|
||||
saveOfflineUser: saveOfflineUser,
|
||||
deleteOfflineUser: deleteOfflineUser,
|
||||
getCameraPhotos: getCameraPhotos,
|
||||
recordUserAction: recordUserAction,
|
||||
getUserActions: getUserActions,
|
||||
deleteUserAction: deleteUserAction,
|
||||
deleteUserActions: deleteUserActions,
|
||||
getServerItemIds: getServerItemIds,
|
||||
removeLocalItem: removeLocalItem,
|
||||
addOrUpdateLocalItem: addOrUpdateLocalItem,
|
||||
createLocalItem: createLocalItem,
|
||||
downloadFile: downloadFile,
|
||||
downloadSubtitles: downloadSubtitles,
|
||||
hasImage: hasImage,
|
||||
downloadImage: downloadImage,
|
||||
fileExists: fileExists,
|
||||
translateFilePath: translateFilePath,
|
||||
getLocalFilePath: getLocalFilePath,
|
||||
getLocalItemById: getLocalItemById
|
||||
};
|
||||
});
|
42
dashboard-ui/bower_components/emby-apiclient/sync/filerepository.js
vendored
Normal file
42
dashboard-ui/bower_components/emby-apiclient/sync/filerepository.js
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getValidFileName(path) {
|
||||
|
||||
// TODO
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
function getFullLocalPath(pathArray) {
|
||||
|
||||
// TODO
|
||||
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);
|
||||
}
|
||||
|
||||
return {
|
||||
getValidFileName: getValidFileName,
|
||||
getFullLocalPath: getFullLocalPath,
|
||||
deleteFile: deleteFile,
|
||||
deleteDirectory: deleteDirectory,
|
||||
fileExists: fileExists,
|
||||
getItemFileSize: getItemFileSize
|
||||
};
|
||||
});
|
97
dashboard-ui/bower_components/emby-apiclient/sync/itemrepository.js
vendored
Normal file
97
dashboard-ui/bower_components/emby-apiclient/sync/itemrepository.js
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
define(['idb'], function () {
|
||||
'use strict';
|
||||
|
||||
// Database name
|
||||
var dbName = "items";
|
||||
|
||||
// Database version
|
||||
var dbVersion = 1;
|
||||
|
||||
var dbPromise;
|
||||
|
||||
function setup() {
|
||||
|
||||
dbPromise = idb.open(dbName, dbVersion, function (upgradeDB) {
|
||||
// Note: we don't use 'break' in this switch statement,
|
||||
// the fall-through behaviour is what we want.
|
||||
switch (upgradeDB.oldVersion) {
|
||||
case 0:
|
||||
upgradeDB.createObjectStore(dbName);
|
||||
//case 1:
|
||||
// upgradeDB.createObjectStore('stuff', { keyPath: '' });
|
||||
}
|
||||
}); //.then(db => console.log("DB opened!", db));
|
||||
}
|
||||
|
||||
function getServerItemIds(serverId) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 10000).then(function (all) {
|
||||
return all.filter(function (item) {
|
||||
return item.ServerId === serverId;
|
||||
}).map(function (item2) {
|
||||
return item2.ItemId;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getServerIds(serverId) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 10000).then(function (all) {
|
||||
return all.filter(function (item) {
|
||||
return item.ServerId === serverId;
|
||||
}).map(function (item2) {
|
||||
return item2.Id;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).get(key);
|
||||
});
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).put(val, key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function remove(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).delete(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).clear(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
return {
|
||||
get: get,
|
||||
set: set,
|
||||
remove: remove,
|
||||
clear: clear,
|
||||
getAll: getAll,
|
||||
getServerItemIds: getServerItemIds,
|
||||
getServerIds: getServerIds
|
||||
};
|
||||
});
|
46
dashboard-ui/bower_components/emby-apiclient/sync/localsync.js
vendored
Normal file
46
dashboard-ui/bower_components/emby-apiclient/sync/localsync.js
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
define(['appSettings', 'connectionManager'], function (appSettings, connectionManager) {
|
||||
'use strict';
|
||||
|
||||
var syncPromise;
|
||||
|
||||
return {
|
||||
|
||||
sync: function (options) {
|
||||
|
||||
if (syncPromise) {
|
||||
return syncPromise;
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['multiserversync'], function (MultiServerSync) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
options.cameraUploadServers = appSettings.cameraUploadServers();
|
||||
|
||||
syncPromise = new MultiServerSync(connectionManager).sync(options).then(function () {
|
||||
|
||||
syncPromise = null;
|
||||
resolve();
|
||||
|
||||
}, function () {
|
||||
|
||||
syncPromise = null;
|
||||
reject();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
getSyncStatus: function () {
|
||||
|
||||
if (syncPromise != null) {
|
||||
return 'Syncing';
|
||||
}
|
||||
return 'Idle';
|
||||
}
|
||||
};
|
||||
|
||||
});
|
@ -1,471 +1,488 @@
|
||||
define(['localassetmanager'], function (LocalAssetManager) {
|
||||
define(['localassetmanager'], function (localassetmanager) {
|
||||
'use strict';
|
||||
|
||||
function processDownloadStatus(apiClient, serverInfo, options) {
|
||||
|
||||
console.log('[mediasync] Begin processDownloadStatus');
|
||||
|
||||
return localassetmanager.getServerItems(serverInfo.Id).then(function (items) {
|
||||
|
||||
console.log('[mediasync] Begin processDownloadStatus getServerItems completed');
|
||||
|
||||
var progressItems = items.filter(function (item) {
|
||||
return item.SyncStatus === 'transferring' || item.SyncStatus === 'queued';
|
||||
});
|
||||
|
||||
var p = Promise.resolve();
|
||||
var cnt = 0;
|
||||
|
||||
progressItems.forEach(function (item) {
|
||||
p = p.then(function () {
|
||||
return reportTransfer(apiClient, item);
|
||||
});
|
||||
cnt++;
|
||||
});
|
||||
|
||||
return p.then(function () {
|
||||
console.log('[mediasync] Exit processDownloadStatus. Items reported: ' + cnt.toString());
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function reportTransfer(apiClient, item) {
|
||||
|
||||
return localassetmanager.getItemFileSize(item.LocalPath).then(function (size) {
|
||||
// The background transfer service on Windows leaves the file empty (size = 0) until it
|
||||
// has been downloaded completely
|
||||
if (size > 0) {
|
||||
return apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function () {
|
||||
item.SyncStatus = 'synced';
|
||||
return localassetmanager.addOrUpdateLocalItem(item);
|
||||
}, function (error) {
|
||||
console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred", error);
|
||||
item.SyncStatus = 'error';
|
||||
return localassetmanager.addOrUpdateLocalItem(item);
|
||||
});
|
||||
} else {
|
||||
return localassetmanager.isDownloadInQueue(item.SyncJobItemId).then(function (result) {
|
||||
if (result) {
|
||||
// just wait for completion
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item.");
|
||||
return localassetmanager.removeLocalItem(item).then(function () {
|
||||
console.log('[mediasync] reportTransfer: Item deleted.');
|
||||
return Promise.resolve();
|
||||
}, function (err2) {
|
||||
console.log('[mediasync] reportTransfer: Failed to delete item.', error);
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}, function (error) {
|
||||
|
||||
console.error('[mediasync] reportTransfer: error on getItemFileSize. Deleting item.', error);
|
||||
return localassetmanager.removeLocalItem(item).then(function () {
|
||||
console.log('[mediasync] reportTransfer: Item deleted.');
|
||||
return Promise.resolve();
|
||||
}, function (err2) {
|
||||
console.log('[mediasync] reportTransfer: Failed to delete item.', error);
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function reportOfflineActions(apiClient, serverInfo) {
|
||||
|
||||
console.log('[mediasync] Begin reportOfflineActions');
|
||||
|
||||
return localassetmanager.getUserActions(serverInfo.Id).then(function (actions) {
|
||||
|
||||
if (!actions.length) {
|
||||
console.log('[mediasync] Exit reportOfflineActions (no actions)');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return apiClient.reportOfflineActions(actions).then(function () {
|
||||
|
||||
return localassetmanager.deleteUserActions(actions).then(function () {
|
||||
console.log('[mediasync] Exit reportOfflineActions (actions reported and deleted.)');
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
|
||||
// delete those actions even on failure, because if the error is caused by
|
||||
// the action data itself, this could otherwise lead to a situation that
|
||||
// never gets resolved
|
||||
console.error('[mediasync] error on apiClient.reportOfflineActions: ' + err.toString());
|
||||
return localassetmanager.deleteUserActions(actions);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncData(apiClient, serverInfo, syncUserItemAccess) {
|
||||
|
||||
console.log('[mediasync] Begin syncData');
|
||||
|
||||
return localassetmanager.getServerItems(serverInfo.Id).then(function (items) {
|
||||
|
||||
var completedItems = items.filter(function (item) {
|
||||
return (item) && ((item.SyncStatus === 'synced') || (item.SyncStatus === 'error'));
|
||||
});
|
||||
|
||||
var request = {
|
||||
TargetId: apiClient.deviceId(),
|
||||
LocalItemIds: completedItems.map(function (xitem) { return xitem.ItemId; }),
|
||||
OfflineUserIds: (serverInfo.Users || []).map(function (u) { return u.Id; })
|
||||
};
|
||||
|
||||
return apiClient.syncData(request).then(function (result) {
|
||||
|
||||
return afterSyncData(apiClient, serverInfo, syncUserItemAccess, result).then(function () {
|
||||
return Promise.resolve();
|
||||
}, function () {
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function afterSyncData(apiClient, serverInfo, enableSyncUserItemAccess, syncDataResult) {
|
||||
|
||||
console.log('[mediasync] Begin afterSyncData');
|
||||
|
||||
var p = Promise.resolve();
|
||||
|
||||
if (syncDataResult.ItemIdsToRemove) {
|
||||
syncDataResult.ItemIdsToRemove.forEach(function (itemId) {
|
||||
p = p.then(function () {
|
||||
return removeLocalItem(itemId, serverInfo.Id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (enableSyncUserItemAccess) {
|
||||
p = p.then(function () {
|
||||
return syncUserItemAccess(syncDataResult, serverInfo.Id);
|
||||
});
|
||||
}
|
||||
|
||||
return p.then(function () {
|
||||
console.log('[mediasync] Exit afterSyncData');
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function removeLocalItem(itemId, serverId) {
|
||||
|
||||
console.log('[mediasync] Begin removeLocalItem');
|
||||
|
||||
return localassetmanager.getLocalItem(serverId, itemId).then(function (item) {
|
||||
|
||||
if (item) {
|
||||
return localassetmanager.removeLocalItem(item);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function getNewMedia(apiClient, serverInfo, options) {
|
||||
|
||||
console.log('[mediasync] Begin getNewMedia');
|
||||
|
||||
return apiClient.getReadySyncItems(apiClient.deviceId()).then(function (jobItems) {
|
||||
|
||||
var p = Promise.resolve();
|
||||
|
||||
jobItems.forEach(function (jobItem) {
|
||||
p = p.then(function () {
|
||||
return getNewItem(jobItem, apiClient, serverInfo, options);
|
||||
});
|
||||
});
|
||||
|
||||
return p.then(function () {
|
||||
console.log('[mediasync] Exit getNewMedia');
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getNewItem(jobItem, apiClient, serverInfo, options) {
|
||||
|
||||
console.log('[mediasync] Begin getNewItem');
|
||||
|
||||
var libraryItem = jobItem.Item;
|
||||
|
||||
return localassetmanager.getLocalItem(serverInfo.Id, libraryItem.Id).then(function (existingItem) {
|
||||
|
||||
console.log('[mediasync] getNewItem.getLocalItem completed');
|
||||
|
||||
if (existingItem) {
|
||||
if (existingItem.SyncStatus === 'queued' || existingItem.SyncStatus === 'transferring' || existingItem.SyncStatus === 'synced') {
|
||||
console.log('[mediasync] getNewItem.getLocalItem found existing item');
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[mediasync] getNewItem.getLocalItem no existing item found');
|
||||
|
||||
return localassetmanager.createLocalItem(libraryItem, serverInfo, jobItem).then(function (localItem) {
|
||||
|
||||
console.log('[mediasync] getNewItem.createLocalItem completed');
|
||||
|
||||
localItem.SyncStatus = 'queued';
|
||||
|
||||
return downloadMedia(apiClient, jobItem, localItem, options).then(function () {
|
||||
|
||||
return getImages(apiClient, jobItem, localItem).then(function () {
|
||||
|
||||
return getSubtitles(apiClient, jobItem, localItem);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function downloadMedia(apiClient, jobItem, localItem, options) {
|
||||
|
||||
console.log('[mediasync] Begin downloadMedia');
|
||||
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
var localPath = localItem.LocalPath;
|
||||
|
||||
console.log('[mediasync] Downloading media. Url: ' + url + '. Local path: ' + localPath);
|
||||
|
||||
options = options || {};
|
||||
|
||||
return localassetmanager.downloadFile(url, localItem).then(function (filename) {
|
||||
|
||||
localItem.SyncStatus = 'transferring';
|
||||
return localassetmanager.addOrUpdateLocalItem(localItem);
|
||||
});
|
||||
}
|
||||
|
||||
function getImages(apiClient, jobItem, localItem) {
|
||||
|
||||
console.log('[mediasync] Begin getImages');
|
||||
|
||||
return getNextImage(0, apiClient, localItem);
|
||||
}
|
||||
|
||||
function getNextImage(index, apiClient, localItem) {
|
||||
|
||||
console.log('[mediasync] Begin getNextImage');
|
||||
|
||||
//if (index >= 4) {
|
||||
|
||||
// deferred.resolve();
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Just for now while media syncing gets worked out
|
||||
return Promise.resolve();
|
||||
|
||||
//var libraryItem = localItem.Item;
|
||||
|
||||
//var serverId = libraryItem.ServerId;
|
||||
//var itemId = null;
|
||||
//var imageTag = null;
|
||||
//var imageType = "Primary";
|
||||
|
||||
//switch (index) {
|
||||
|
||||
// case 0:
|
||||
// itemId = libraryItem.Id;
|
||||
// imageType = "Primary";
|
||||
// imageTag = (libraryItem.ImageTags || {})["Primary"];
|
||||
// break;
|
||||
// case 1:
|
||||
// itemId = libraryItem.SeriesId;
|
||||
// imageType = "Primary";
|
||||
// imageTag = libraryItem.SeriesPrimaryImageTag;
|
||||
// break;
|
||||
// case 2:
|
||||
// itemId = libraryItem.SeriesId;
|
||||
// imageType = "Thumb";
|
||||
// imageTag = libraryItem.SeriesPrimaryImageTag;
|
||||
// break;
|
||||
// case 3:
|
||||
// itemId = libraryItem.AlbumId;
|
||||
// imageType = "Primary";
|
||||
// imageTag = libraryItem.AlbumPrimaryImageTag;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
//}
|
||||
|
||||
//if (!itemId || !imageTag) {
|
||||
// getNextImage(index + 1, apiClient, localItem, deferred);
|
||||
// return;
|
||||
//}
|
||||
|
||||
//downloadImage(apiClient, serverId, itemId, imageTag, imageType).then(function () {
|
||||
|
||||
// // For the sake of simplicity, limit to one image
|
||||
// deferred.resolve();
|
||||
// return;
|
||||
|
||||
// getNextImage(index + 1, apiClient, localItem, deferred);
|
||||
|
||||
//}, getOnFail(deferred));
|
||||
}
|
||||
|
||||
function downloadImage(apiClient, serverId, itemId, imageTag, imageType) {
|
||||
|
||||
console.log('[mediasync] Begin downloadImage');
|
||||
|
||||
return localassetmanager.hasImage(serverId, itemId, imageTag).then(function (hasImage) {
|
||||
|
||||
if (hasImage) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var imageUrl = apiClient.getImageUrl(itemId, {
|
||||
tag: imageTag,
|
||||
type: imageType,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
return localassetmanager.downloadImage(imageUrl, serverId, itemId, imageTag);
|
||||
});
|
||||
}
|
||||
|
||||
function getSubtitles(apiClient, jobItem, localItem) {
|
||||
|
||||
console.log('[mediasync] Begin getSubtitles');
|
||||
|
||||
if (!jobItem.Item.MediaSources.length) {
|
||||
console.log("[mediasync] Cannot download subtitles because video has no media source info.");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var files = jobItem.AdditionalFiles.filter(function (f) {
|
||||
return f.Type === 'Subtitles';
|
||||
});
|
||||
|
||||
var mediaSource = jobItem.Item.MediaSources[0];
|
||||
|
||||
var p = Promise.resolve();
|
||||
|
||||
files.forEach(function (file) {
|
||||
p = p.then(function () {
|
||||
return getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource);
|
||||
});
|
||||
});
|
||||
|
||||
return p.then(function () {
|
||||
console.log('[mediasync] Exit getSubtitles');
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
|
||||
|
||||
console.log('[mediasync] Begin getItemSubtitle');
|
||||
|
||||
var subtitleStream = mediaSource.MediaStreams.filter(function (m) {
|
||||
return m.Type === 'Subtitle' && m.Index === file.Index;
|
||||
})[0];
|
||||
|
||||
if (!subtitleStream) {
|
||||
|
||||
// We shouldn't get in here, but let's just be safe anyway
|
||||
console.log("[mediasync] Cannot download subtitles because matching stream info wasn't found.");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
|
||||
Name: file.Name,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
var fileName = localassetmanager.getSubtitleSaveFileName(jobItem.OriginalFileName, subtitleStream.Language, subtitleStream.IsForced, subtitleStream.Codec);
|
||||
var localFilePath = localassetmanager.getLocalFilePath(localItem, fileName);
|
||||
|
||||
return localassetmanager.downloadSubtitles(url, localFilePath).then(function (subtitlePath) {
|
||||
|
||||
subtitleStream.Path = subtitlePath;
|
||||
return localassetmanager.addOrUpdateLocalItem(localItem);
|
||||
});
|
||||
}
|
||||
|
||||
return function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.sync = function (apiClient, serverInfo, options) {
|
||||
|
||||
return reportOfflineActions(apiClient, serverInfo).then(function () {
|
||||
console.log("[mediasync]************************************* Start sync");
|
||||
|
||||
// Do the first data sync
|
||||
return syncData(apiClient, serverInfo, false).then(function () {
|
||||
return processDownloadStatus(apiClient, serverInfo, options).then(function () {
|
||||
|
||||
return reportOfflineActions(apiClient, serverInfo).then(function () {
|
||||
|
||||
//// Do the first data sync
|
||||
//return syncData(apiClient, serverInfo, false).then(function () {
|
||||
|
||||
// Download new content
|
||||
return getNewMedia(apiClient, serverInfo, options).then(function () {
|
||||
|
||||
// Do the second data sync
|
||||
return syncData(apiClient, serverInfo, false);
|
||||
return syncData(apiClient, serverInfo, false).then(function () {
|
||||
console.log("[mediasync]************************************* Exit sync");
|
||||
});
|
||||
});
|
||||
//});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function reportOfflineActions(apiClient, serverInfo) {
|
||||
|
||||
console.log('Begin reportOfflineActions');
|
||||
|
||||
return LocalAssetManager.getOfflineActions(serverInfo.Id).then(function (actions) {
|
||||
|
||||
if (!actions.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return apiClient.reportOfflineActions(actions).then(function () {
|
||||
|
||||
return LocalAssetManager.deleteOfflineActions(actions);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncData(apiClient, serverInfo, syncUserItemAccess) {
|
||||
|
||||
console.log('Begin syncData');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
LocalAssetManager.getServerItemIds(serverInfo.Id).then(function (localIds) {
|
||||
|
||||
var request = {
|
||||
TargetId: apiClient.deviceId(),
|
||||
LocalItemIds: localIds,
|
||||
OfflineUserIds: (serverInfo.Users || []).map(function (u) { return u.Id; })
|
||||
};
|
||||
|
||||
apiClient.syncData(request).then(function (result) {
|
||||
|
||||
afterSyncData(apiClient, serverInfo, syncUserItemAccess, result, deferred);
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function afterSyncData(apiClient, serverInfo, enableSyncUserItemAccess, syncDataResult, deferred) {
|
||||
|
||||
console.log('Begin afterSyncData');
|
||||
|
||||
removeLocalItems(syncDataResult, serverInfo.Id).then(function (result) {
|
||||
|
||||
if (enableSyncUserItemAccess) {
|
||||
syncUserItemAccess(syncDataResult, serverInfo.Id).then(function () {
|
||||
|
||||
deferred.resolve();
|
||||
|
||||
}, getOnFail(deferred));
|
||||
}
|
||||
else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
function removeLocalItems(syncDataResult, serverId) {
|
||||
|
||||
console.log('Begin removeLocalItems');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
removeNextLocalItem(syncDataResult.ItemIdsToRemove, 0, serverId, deferred);
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function removeNextLocalItem(itemIdsToRemove, index, serverId, deferred) {
|
||||
|
||||
var length = itemIdsToRemove.length;
|
||||
|
||||
if (index >= length) {
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
removeLocalItem(itemIdsToRemove[index], serverId).then(function () {
|
||||
|
||||
removeNextLocalItem(itemIdsToRemove, index + 1, serverId, deferred);
|
||||
}, function () {
|
||||
removeNextLocalItem(itemIdsToRemove, index + 1, serverId, deferred);
|
||||
});
|
||||
}
|
||||
|
||||
function removeLocalItem(itemId, serverId) {
|
||||
|
||||
console.log('Begin removeLocalItem');
|
||||
|
||||
return LocalAssetManager.removeLocalItem(itemId, serverId);
|
||||
}
|
||||
|
||||
function getNewMedia(apiClient, serverInfo, options) {
|
||||
|
||||
console.log('Begin getNewMedia');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
apiClient.getReadySyncItems(apiClient.deviceId()).then(function (jobItems) {
|
||||
|
||||
getNextNewItem(jobItems, 0, apiClient, serverInfo, options, deferred);
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getNextNewItem(jobItems, index, apiClient, serverInfo, options, deferred) {
|
||||
|
||||
var length = jobItems.length;
|
||||
|
||||
if (index >= length) {
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var hasGoneNext = false;
|
||||
var goNext = function () {
|
||||
|
||||
if (!hasGoneNext) {
|
||||
hasGoneNext = true;
|
||||
getNextNewItem(jobItems, index + 1, apiClient, serverInfo, options, deferred);
|
||||
}
|
||||
};
|
||||
|
||||
getNewItem(jobItems[index], apiClient, serverInfo, options).then(goNext, goNext);
|
||||
}
|
||||
|
||||
function getNewItem(jobItem, apiClient, serverInfo, options) {
|
||||
|
||||
console.log('Begin getNewItem');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var libraryItem = jobItem.Item;
|
||||
LocalAssetManager.createLocalItem(libraryItem, serverInfo, jobItem.OriginalFileName).then(function (localItem) {
|
||||
|
||||
downloadMedia(apiClient, jobItem, localItem, options).then(function (isQueued) {
|
||||
|
||||
if (isQueued) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
getImages(apiClient, jobItem, localItem).then(function () {
|
||||
|
||||
getSubtitles(apiClient, jobItem, localItem).then(function () {
|
||||
|
||||
apiClient.reportSyncJobItemTransferred(jobItem.SyncJobItemId).then(function () {
|
||||
|
||||
deferred.resolve();
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function downloadMedia(apiClient, jobItem, localItem, options) {
|
||||
|
||||
console.log('Begin downloadMedia');
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
var localPath = localItem.LocalPath;
|
||||
|
||||
console.log('Downloading media. Url: ' + url + '. Local path: ' + localPath);
|
||||
|
||||
options = options || {};
|
||||
|
||||
LocalAssetManager.downloadFile(url, localPath, options.enableBackgroundTransfer, options.enableNewDownloads).then(function (path, isQueued) {
|
||||
|
||||
if (isQueued) {
|
||||
deferred.resolveWith(null, [true]);
|
||||
return;
|
||||
}
|
||||
LocalAssetManager.addOrUpdateLocalItem(localItem).then(function () {
|
||||
|
||||
deferred.resolveWith(null, [false]);
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getImages(apiClient, jobItem, localItem) {
|
||||
|
||||
console.log('Begin getImages');
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
getNextImage(0, apiClient, localItem, deferred);
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getNextImage(index, apiClient, localItem, deferred) {
|
||||
|
||||
console.log('Begin getNextImage');
|
||||
if (index >= 4) {
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// Just for now while media syncing gets worked out
|
||||
deferred.resolve();
|
||||
|
||||
//var libraryItem = localItem.Item;
|
||||
|
||||
//var serverId = libraryItem.ServerId;
|
||||
//var itemId = null;
|
||||
//var imageTag = null;
|
||||
//var imageType = "Primary";
|
||||
|
||||
//switch (index) {
|
||||
|
||||
// case 0:
|
||||
// itemId = libraryItem.Id;
|
||||
// imageType = "Primary";
|
||||
// imageTag = (libraryItem.ImageTags || {})["Primary"];
|
||||
// break;
|
||||
// case 1:
|
||||
// itemId = libraryItem.SeriesId;
|
||||
// imageType = "Primary";
|
||||
// imageTag = libraryItem.SeriesPrimaryImageTag;
|
||||
// break;
|
||||
// case 2:
|
||||
// itemId = libraryItem.SeriesId;
|
||||
// imageType = "Thumb";
|
||||
// imageTag = libraryItem.SeriesPrimaryImageTag;
|
||||
// break;
|
||||
// case 3:
|
||||
// itemId = libraryItem.AlbumId;
|
||||
// imageType = "Primary";
|
||||
// imageTag = libraryItem.AlbumPrimaryImageTag;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
//}
|
||||
|
||||
//if (!itemId || !imageTag) {
|
||||
// getNextImage(index + 1, apiClient, localItem, deferred);
|
||||
// return;
|
||||
//}
|
||||
|
||||
//downloadImage(apiClient, serverId, itemId, imageTag, imageType).then(function () {
|
||||
|
||||
// // For the sake of simplicity, limit to one image
|
||||
// deferred.resolve();
|
||||
// return;
|
||||
|
||||
// getNextImage(index + 1, apiClient, localItem, deferred);
|
||||
|
||||
//}, getOnFail(deferred));
|
||||
}
|
||||
|
||||
function downloadImage(apiClient, serverId, itemId, imageTag, imageType) {
|
||||
|
||||
console.log('Begin downloadImage');
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
LocalAssetManager.hasImage(serverId, itemId, imageTag).then(function (hasImage) {
|
||||
|
||||
if (hasImage) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var imageUrl = apiClient.getImageUrl(itemId, {
|
||||
tag: imageTag,
|
||||
type: imageType,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
LocalAssetManager.downloadImage(imageUrl, serverId, itemId, imageTag).then(function () {
|
||||
|
||||
deferred.resolve();
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getSubtitles(apiClient, jobItem, localItem) {
|
||||
|
||||
console.log('Begin getSubtitles');
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
if (!jobItem.Item.MediaSources.length) {
|
||||
console.log("Cannot download subtitles because video has no media source info.");
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var files = jobItem.AdditionalFiles.filter(function (f) {
|
||||
return f.Type === 'Subtitles';
|
||||
});
|
||||
|
||||
var mediaSource = jobItem.Item.MediaSources[0];
|
||||
|
||||
getNextSubtitle(files, 0, apiClient, jobItem, localItem, mediaSource, deferred);
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getNextSubtitle(files, index, apiClient, jobItem, localItem, mediaSource, deferred) {
|
||||
|
||||
var length = files.length;
|
||||
|
||||
if (index >= length) {
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource).then(function () {
|
||||
|
||||
getNextSubtitle(files, index + 1, apiClient, jobItem, localItem, mediaSource, deferred);
|
||||
|
||||
}, function () {
|
||||
getNextSubtitle(files, index + 1, apiClient, jobItem, localItem, mediaSource, deferred);
|
||||
});
|
||||
}
|
||||
|
||||
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
|
||||
|
||||
console.log('Begin getItemSubtitle');
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var subtitleStream = mediaSource.MediaStreams.filter(function (m) {
|
||||
return m.Type === 'Subtitle' && m.Index === file.Index;
|
||||
})[0];
|
||||
|
||||
if (!subtitleStream) {
|
||||
|
||||
// We shouldn't get in here, but let's just be safe anyway
|
||||
console.log("Cannot download subtitles because matching stream info wasn't found.");
|
||||
deferred.reject();
|
||||
return;
|
||||
}
|
||||
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
|
||||
Name: file.Name,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
|
||||
LocalAssetManager.downloadSubtitles(url, localItem, subtitleStream).then(function (subtitlePath) {
|
||||
|
||||
subtitleStream.Path = subtitlePath;
|
||||
LocalAssetManager.addOrUpdateLocalItem(localItem).then(function () {
|
||||
deferred.resolve();
|
||||
}, getOnFail(deferred));
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function syncUserItemAccess(syncDataResult, serverId) {
|
||||
console.log('Begin syncUserItemAccess');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var itemIds = [];
|
||||
for (var id in syncDataResult.ItemUserAccess) {
|
||||
itemIds.push(id);
|
||||
}
|
||||
|
||||
syncNextUserAccessForItem(itemIds, 0, syncDataResult, serverId, deferred);
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function syncNextUserAccessForItem(itemIds, index, syncDataResult, serverId, deferred) {
|
||||
|
||||
var length = itemIds.length;
|
||||
|
||||
if (index >= length) {
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
syncUserAccessForItem(itemIds[index], syncDataResult).then(function () {
|
||||
|
||||
syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
|
||||
}, function () {
|
||||
syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
|
||||
});
|
||||
}
|
||||
|
||||
function syncUserAccessForItem(itemId, syncDataResult) {
|
||||
console.log('Begin syncUserAccessForItem');
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
LocalAssetManager.getUserIdsWithAccess(itemId, serverId).then(function (savedUserIdsWithAccess) {
|
||||
|
||||
var userIdsWithAccess = syncDataResult.ItemUserAccess[itemId];
|
||||
|
||||
if (userIdsWithAccess.join(',') === savedUserIdsWithAccess.join(',')) {
|
||||
// Hasn't changed, nothing to do
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
|
||||
LocalAssetManager.saveUserIdsWithAccess(itemId, serverId, userIdsWithAccess).then(function () {
|
||||
deferred.resolve();
|
||||
}, getOnFail(deferred));
|
||||
}
|
||||
|
||||
}, getOnFail(deferred));
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function getOnFail(deferred) {
|
||||
return function () {
|
||||
|
||||
deferred.reject();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//function syncUserItemAccess(syncDataResult, serverId) {
|
||||
// console.log('[mediasync] Begin syncUserItemAccess');
|
||||
|
||||
// var itemIds = [];
|
||||
// for (var id in syncDataResult.ItemUserAccess) {
|
||||
// itemIds.push(id);
|
||||
// }
|
||||
|
||||
// return syncNextUserAccessForItem(itemIds, 0, syncDataResult, serverId);
|
||||
//}
|
||||
|
||||
//function syncNextUserAccessForItem(itemIds, index, syncDataResult, serverId) {
|
||||
|
||||
// var length = itemIds.length;
|
||||
|
||||
// if (index >= length) {
|
||||
|
||||
// return Promise.resolve
|
||||
// return;
|
||||
// }
|
||||
|
||||
// syncUserAccessForItem(itemIds[index], syncDataResult).then(function () {
|
||||
|
||||
// syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
|
||||
// }, function () {
|
||||
// syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
|
||||
// });
|
||||
//}
|
||||
|
||||
//function syncUserAccessForItem(itemId, syncDataResult) {
|
||||
// console.log('[mediasync] Begin syncUserAccessForItem');
|
||||
|
||||
// var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
// localassetmanager.getUserIdsWithAccess(itemId, serverId).then(function (savedUserIdsWithAccess) {
|
||||
|
||||
// var userIdsWithAccess = syncDataResult.ItemUserAccess[itemId];
|
||||
|
||||
// if (userIdsWithAccess.join(',') === savedUserIdsWithAccess.join(',')) {
|
||||
// // Hasn't changed, nothing to do
|
||||
// deferred.resolve();
|
||||
// }
|
||||
// else {
|
||||
|
||||
// localassetmanager.saveUserIdsWithAccess(itemId, serverId, userIdsWithAccess).then(function () {
|
||||
// deferred.resolve();
|
||||
// }, getOnFail(deferred));
|
||||
// }
|
||||
|
||||
// }, getOnFail(deferred));
|
||||
|
||||
// return deferred.promise();
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
});
|
@ -16,7 +16,8 @@
|
||||
var connectionOptions = {
|
||||
updateDateLastAccessed: false,
|
||||
enableWebSocket: false,
|
||||
reportCapabilities: false
|
||||
reportCapabilities: false,
|
||||
enableAutomaticBitrateDetection: false
|
||||
};
|
||||
|
||||
return connectionManager.connectToServer(server, connectionOptions).then(function (result) {
|
||||
@ -37,7 +38,7 @@
|
||||
|
||||
function performSync(server, options) {
|
||||
|
||||
console.log("Creating ContentUploader to server: " + server.Id);
|
||||
console.log("ServerSync.performSync to server: " + server.Id);
|
||||
|
||||
options = options || {};
|
||||
|
||||
@ -47,34 +48,27 @@
|
||||
uploadPhotos = false;
|
||||
}
|
||||
|
||||
if (!uploadPhotos) {
|
||||
return syncOfflineUsers(server, options);
|
||||
}
|
||||
var pr = syncOfflineUsers(server, options);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
return pr.then(function () {
|
||||
|
||||
require(['contentuploader'], function (ContentUploader) {
|
||||
if (uploadPhotos) {
|
||||
return uploadContent(server, options);
|
||||
}
|
||||
|
||||
new ContentUploader(connectionManager).uploadImages(server).then(function () {
|
||||
return Promise.resolve();
|
||||
|
||||
console.log("ContentUploaded succeeded to server: " + server.Id);
|
||||
}).then(function () {
|
||||
|
||||
syncOfflineUsers(server, options).then(resolve, reject);
|
||||
|
||||
}, function () {
|
||||
|
||||
console.log("ContentUploaded failed to server: " + server.Id);
|
||||
|
||||
syncOfflineUsers(server, options).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
return syncMedia(server, options);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function syncOfflineUsers(server, options) {
|
||||
|
||||
if (options.syncOfflineUsers === false) {
|
||||
return syncMedia(server, options);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
@ -83,13 +77,19 @@
|
||||
|
||||
var apiClient = connectionManager.getApiClient(server.Id);
|
||||
|
||||
new OfflineUserSync().sync(apiClient, server).then(function () {
|
||||
new OfflineUserSync().sync(apiClient, server).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
console.log("OfflineUserSync succeeded to server: " + server.Id);
|
||||
function uploadContent(server, options) {
|
||||
|
||||
syncMedia(server, options).then(resolve, reject);
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
}, reject);
|
||||
require(['contentuploader'], function (contentuploader) {
|
||||
|
||||
uploader = new ContentUploader(connectionManager);
|
||||
uploader.uploadImages(server).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
23
dashboard-ui/bower_components/emby-apiclient/sync/transfermanager.js
vendored
Normal file
23
dashboard-ui/bower_components/emby-apiclient/sync/transfermanager.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
define(['filerepository'], function (filerepository) {
|
||||
'use strict';
|
||||
|
||||
function downloadFile(url, localPath) {
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function downloadSubtitles(url, localItem, subtitleStreamh) {
|
||||
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
function downloadImage(url, serverId, itemId, imageTag) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
return {
|
||||
downloadFile: downloadFile,
|
||||
downloadSubtitles: downloadSubtitles,
|
||||
downloadImage: downloadImage
|
||||
};
|
||||
});
|
82
dashboard-ui/bower_components/emby-apiclient/sync/useractionrepository.js
vendored
Normal file
82
dashboard-ui/bower_components/emby-apiclient/sync/useractionrepository.js
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
define(['idb'], function () {
|
||||
'use strict';
|
||||
|
||||
// Database name
|
||||
var dbName = "useractions";
|
||||
|
||||
// Database version
|
||||
var dbVersion = 1;
|
||||
|
||||
var dbPromise;
|
||||
|
||||
function setup() {
|
||||
|
||||
dbPromise = idb.open(dbName, dbVersion, function (upgradeDB) {
|
||||
// Note: we don't use 'break' in this switch statement,
|
||||
// the fall-through behaviour is what we want.
|
||||
switch (upgradeDB.oldVersion) {
|
||||
case 0:
|
||||
upgradeDB.createObjectStore(dbName);
|
||||
//case 1:
|
||||
// upgradeDB.createObjectStore('stuff', { keyPath: '' });
|
||||
}
|
||||
}); //.then(db => console.log("DB opened!", db));
|
||||
}
|
||||
|
||||
function getByServerId(serverId) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 1000).then(function (all) {
|
||||
return all.filter(function (item) {
|
||||
return item.ServerId === serverId;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).get(key);
|
||||
});
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).put(val, key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function remove(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).delete(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).clear(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
return {
|
||||
get: get,
|
||||
set: set,
|
||||
remove: remove,
|
||||
clear: clear,
|
||||
getAll: getAll,
|
||||
getByServerId: getByServerId
|
||||
};
|
||||
});
|
71
dashboard-ui/bower_components/emby-apiclient/sync/userrepository.js
vendored
Normal file
71
dashboard-ui/bower_components/emby-apiclient/sync/userrepository.js
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
define(['idb'], function () {
|
||||
'use strict';
|
||||
|
||||
// Database name
|
||||
var dbName = "users";
|
||||
|
||||
// Database version
|
||||
var dbVersion = 1;
|
||||
|
||||
var dbPromise;
|
||||
|
||||
function setup() {
|
||||
|
||||
dbPromise = idb.open(dbName, dbVersion, function (upgradeDB) {
|
||||
// Note: we don't use 'break' in this switch statement,
|
||||
// the fall-through behaviour is what we want.
|
||||
switch (upgradeDB.oldVersion) {
|
||||
case 0:
|
||||
upgradeDB.createObjectStore(dbName);
|
||||
//case 1:
|
||||
// upgradeDB.createObjectStore('stuff', { keyPath: '' });
|
||||
}
|
||||
}); //.then(db => console.log("DB opened!", db));
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).getAll(null, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
return db.transaction(dbName).objectStore(dbName).get(key);
|
||||
});
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).put(val, key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function remove(key) {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).delete(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
return dbPromise.then(function (db) {
|
||||
var tx = db.transaction(dbName, 'readwrite');
|
||||
tx.objectStore(dbName).clear(key);
|
||||
return tx.complete;
|
||||
});
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
return {
|
||||
get: get,
|
||||
set: set,
|
||||
remove: remove,
|
||||
clear: clear,
|
||||
getAll: getAll
|
||||
};
|
||||
});
|
@ -14,12 +14,12 @@
|
||||
},
|
||||
"devDependencies": {},
|
||||
"ignore": [],
|
||||
"version": "1.4.321",
|
||||
"_release": "1.4.321",
|
||||
"version": "1.4.390",
|
||||
"_release": "1.4.390",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.4.321",
|
||||
"commit": "fb270e69c8391f62e762ee03d77a7b8a495c5a6f"
|
||||
"tag": "1.4.390",
|
||||
"commit": "075f424628a8208d15eca0ed024fe4d8f6bf43fa"
|
||||
},
|
||||
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
|
||||
"_target": "^1.2.1",
|
||||
|
@ -140,7 +140,7 @@
|
||||
var html = '';
|
||||
|
||||
var scrollType = layoutManager.desktop ? 'smoothScrollY' : 'hiddenScrollY';
|
||||
var style = (browser.noFlex || browser.firefox) ? 'max-height:400px;' : '';
|
||||
var style = (browser.firefox) ? 'max-height:400px;' : '';
|
||||
|
||||
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
|
||||
if (options.items.length > 20) {
|
||||
@ -193,7 +193,7 @@
|
||||
|
||||
html += '<div class="actionSheetScroller ' + scrollType + '" style="' + style + '">';
|
||||
|
||||
var menuItemClass = browser.noFlex || browser.firefox ? 'actionSheetMenuItem actionSheetMenuItem-noflex' : 'actionSheetMenuItem';
|
||||
var menuItemClass = browser.firefox ? 'actionSheetMenuItem actionSheetMenuItem-noflex' : 'actionSheetMenuItem';
|
||||
|
||||
if (options.menuItemClass) {
|
||||
menuItemClass += ' ' + options.menuItemClass;
|
||||
|
@ -40,7 +40,7 @@
|
||||
backdropImage.style.backgroundImage = "url('" + url + "')";
|
||||
backdropImage.setAttribute('data-url', url);
|
||||
|
||||
backdropImage.style.animation = 'backdrop-fadein ' + 800 + 'ms ease-in normal both';
|
||||
backdropImage.classList.add('backdropImageFadeIn');
|
||||
parent.appendChild(backdropImage);
|
||||
|
||||
if (!enableAnimation(backdropImage)) {
|
||||
@ -52,7 +52,7 @@
|
||||
}
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(backdropImage, 'animationend', onAnimationComplete, {
|
||||
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
if (backdropImage === currentAnimatingElement) {
|
||||
@ -63,7 +63,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
dom.addEventListener(backdropImage, 'animationend', onAnimationComplete, {
|
||||
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
function cancelAnimation() {
|
||||
var elem = currentAnimatingElement;
|
||||
if (elem) {
|
||||
elem.style.animation = '';
|
||||
elem.classList.remove('backdropImageFadeIn');
|
||||
currentAnimatingElement = null;
|
||||
}
|
||||
}
|
||||
@ -176,7 +176,24 @@
|
||||
currentLoadingBackdrop = instance;
|
||||
}
|
||||
|
||||
function getItemImageUrls(item) {
|
||||
var standardWidths = [480, 720, 1280, 1440, 1920];
|
||||
function getBackdropMaxWidth() {
|
||||
|
||||
var width = dom.getWindowSize().innerWidth;
|
||||
|
||||
if (standardWidths.indexOf(width) !== -1) {
|
||||
return width;
|
||||
}
|
||||
|
||||
var roundScreenTo = 100;
|
||||
width = Math.floor(width / roundScreenTo) * roundScreenTo;
|
||||
|
||||
return Math.min(width, 1920);
|
||||
}
|
||||
|
||||
function getItemImageUrls(item, imageOptions) {
|
||||
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
@ -184,12 +201,12 @@
|
||||
|
||||
return item.BackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
return apiClient.getScaledImageUrl(item.Id, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: Math.min(dom.getWindowSize().innerWidth, 1920),
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@ -197,19 +214,19 @@
|
||||
|
||||
return item.ParentBackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: Math.min(dom.getWindowSize().innerWidth, 1920),
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function getImageUrls(items) {
|
||||
function getImageUrls(items, imageOptions) {
|
||||
|
||||
var list = [];
|
||||
|
||||
@ -219,7 +236,7 @@
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var itemImages = getItemImageUrls(items[i]);
|
||||
var itemImages = getItemImageUrls(items[i], imageOptions);
|
||||
|
||||
itemImages.forEach(onImg);
|
||||
}
|
||||
@ -252,21 +269,20 @@
|
||||
var rotationInterval;
|
||||
var currentRotatingImages = [];
|
||||
var currentRotationIndex = -1;
|
||||
function setBackdrops(items, imageSetId) {
|
||||
function setBackdrops(items, imageOptions, enableImageRotation) {
|
||||
|
||||
var images = getImageUrls(items);
|
||||
var images = getImageUrls(items, imageOptions);
|
||||
|
||||
imageSetId = imageSetId || new Date().getTime();
|
||||
if (images.length) {
|
||||
|
||||
startRotation(images, imageSetId);
|
||||
startRotation(images, enableImageRotation);
|
||||
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
function startRotation(images) {
|
||||
function startRotation(images, enableImageRotation) {
|
||||
|
||||
if (arraysEqual(images, currentRotatingImages)) {
|
||||
return;
|
||||
@ -277,7 +293,7 @@
|
||||
currentRotatingImages = images;
|
||||
currentRotationIndex = -1;
|
||||
|
||||
if (images.length > 1 && enableRotation()) {
|
||||
if (images.length > 1 && enableImageRotation !== false && enableRotation()) {
|
||||
rotationInterval = setInterval(onRotationInterval, 20000);
|
||||
}
|
||||
onRotationInterval();
|
||||
@ -308,10 +324,12 @@
|
||||
currentRotationIndex = -1;
|
||||
}
|
||||
|
||||
function setBackdrop(url) {
|
||||
function setBackdrop(url, imageOptions) {
|
||||
|
||||
if (typeof url !== 'string') {
|
||||
url = getImageUrls([url])[0];
|
||||
if (url) {
|
||||
if (typeof url !== 'string') {
|
||||
url = getImageUrls([url], imageOptions)[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (url) {
|
||||
|
@ -15,6 +15,10 @@
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.backdropImageFadeIn {
|
||||
animation: backdrop-fadein 800ms ease-in normal both;
|
||||
}
|
||||
|
||||
@keyframes backdrop-fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
@ -23,4 +27,4 @@
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,11 @@
|
||||
}
|
||||
|
||||
function isStyleSupported(prop, value) {
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If no value is supplied, use "inherit"
|
||||
value = arguments.length === 2 ? value : 'inherit';
|
||||
// Try the native standard method first
|
||||
@ -116,6 +121,50 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
var _supportsCssAnimation;
|
||||
var _supportsCssAnimationWithPrefix;
|
||||
function supportsCssAnimation(allowPrefix) {
|
||||
|
||||
if (allowPrefix) {
|
||||
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
|
||||
return _supportsCssAnimationWithPrefix;
|
||||
}
|
||||
} else {
|
||||
if (_supportsCssAnimation === true || _supportsCssAnimation === false) {
|
||||
return _supportsCssAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
var animation = false,
|
||||
animationstring = 'animation',
|
||||
keyframeprefix = '',
|
||||
domPrefixes = ['Webkit', 'O', 'Moz'],
|
||||
pfx = '',
|
||||
elm = document.createElement('div');
|
||||
|
||||
if (elm.style.animationName !== undefined) { animation = true; }
|
||||
|
||||
if (animation === false && allowPrefix) {
|
||||
for (var i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
|
||||
pfx = domPrefixes[i];
|
||||
animationstring = pfx + 'Animation';
|
||||
keyframeprefix = '-' + pfx.toLowerCase() + '-';
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowPrefix) {
|
||||
_supportsCssAnimationWithPrefix = animation;
|
||||
return _supportsCssAnimationWithPrefix;
|
||||
} else {
|
||||
_supportsCssAnimation = animation;
|
||||
return _supportsCssAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
var uaMatch = function (ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
@ -176,7 +225,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
var userAgent = window.navigator.userAgent;
|
||||
var userAgent = navigator.userAgent;
|
||||
var matched = uaMatch(userAgent);
|
||||
var browser = {};
|
||||
|
||||
@ -204,7 +253,7 @@
|
||||
}
|
||||
|
||||
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
|
||||
browser.animate = document.documentElement.animate != null;
|
||||
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
||||
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || userAgent.toLowerCase().indexOf('smarthub') !== -1;
|
||||
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
|
||||
browser.edgeUwp = browser.edge && userAgent.toLowerCase().indexOf('msapphost') !== -1;
|
||||
@ -220,11 +269,17 @@
|
||||
browser.slow = true;
|
||||
}
|
||||
|
||||
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
|
||||
browser.touch = true;
|
||||
if (typeof document !== 'undefined') {
|
||||
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
|
||||
browser.touch = true;
|
||||
}
|
||||
}
|
||||
|
||||
browser.keyboard = hasKeyboard(browser);
|
||||
browser.supportsCssAnimation = supportsCssAnimation;
|
||||
|
||||
browser.osx = userAgent.toLowerCase().indexOf('os x') !== -1;
|
||||
browser.iOS = browser.ipad || browser.iphone || browser.ipod;
|
||||
|
||||
return browser;
|
||||
});
|
@ -53,7 +53,7 @@ button {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cardPadder-backdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop {
|
||||
.cardPadder-backdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop, .cardPadder-overflowSmallBackdrop {
|
||||
padding-bottom: 56.25%;
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ button {
|
||||
|
||||
.btnCardOptions {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
bottom: .25em;
|
||||
right: 0;
|
||||
margin: 0 !important;
|
||||
z-index: 1;
|
||||
@ -133,7 +133,6 @@ button {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: -ms-flex;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -403,12 +402,16 @@ button {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.overflowSquareCard-scalable {
|
||||
width: 42%;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
@media all and (min-width: 420px) {
|
||||
@media all and (min-width: 400px) {
|
||||
|
||||
.backdropCard-scalable {
|
||||
width: 50%;
|
||||
@ -439,6 +442,10 @@ button {
|
||||
.overflowSquareCard-scalable {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 40%
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 640px) {
|
||||
@ -450,6 +457,10 @@ button {
|
||||
.overflowBackdropCard-scalable {
|
||||
width: 56%;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 40%
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 700px) {
|
||||
@ -462,6 +473,10 @@ button {
|
||||
.backdropCard-scalable {
|
||||
width: 33.333333333333333333333333333333%;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 30%
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 800px) {
|
||||
@ -502,6 +517,10 @@ button {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 24%
|
||||
}
|
||||
|
||||
.overflowSquareCard-scalable {
|
||||
width: 22%;
|
||||
}
|
||||
@ -528,6 +547,10 @@ button {
|
||||
.smallBackdropCard-scalable {
|
||||
width: 16.666666666666666666666666666667%;
|
||||
}
|
||||
|
||||
.overflowSmallBackdropCard-scalable {
|
||||
width: 18%
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo', 'focusManager', 'indicators', 'globalize', 'layoutManager', 'apphost', 'dom', 'emby-button', 'css!./card', 'paper-icon-button-light', 'clearButtonStyle'],
|
||||
function (datetime, imageLoader, connectionManager, itemHelper, mediaInfo, focusManager, indicators, globalize, layoutManager, appHost, dom) {
|
||||
define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusManager', 'indicators', 'globalize', 'layoutManager', 'apphost', 'dom', 'browser', 'emby-button', 'css!./card', 'paper-icon-button-light', 'clearButtonStyle'],
|
||||
function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser) {
|
||||
'use strict';
|
||||
|
||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
||||
@ -144,6 +144,20 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
return 100 / 64;
|
||||
}
|
||||
return 100 / 72;
|
||||
case 'overflowSmallBackdrop':
|
||||
if (screenWidth >= 1200) {
|
||||
return 100 / 18;
|
||||
}
|
||||
if (screenWidth >= 1000) {
|
||||
return 100 / 24;
|
||||
}
|
||||
if (screenWidth >= 770) {
|
||||
return 100 / 30;
|
||||
}
|
||||
if (screenWidth >= 540) {
|
||||
return 100 / 40;
|
||||
}
|
||||
return 100 / 60;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@ -689,7 +703,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
return 'defaultCardColor' + getDefaultColorIndex(str);
|
||||
}
|
||||
|
||||
function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin) {
|
||||
function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) {
|
||||
|
||||
var html = '';
|
||||
|
||||
@ -714,10 +728,17 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
html += text;
|
||||
html += "</div>";
|
||||
valid++;
|
||||
|
||||
if (maxLines && valid >= maxLines) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forceLines) {
|
||||
|
||||
length = Math.min(lines.length, maxLines || lines.length);
|
||||
|
||||
while (valid < length) {
|
||||
html += "<div class='" + cssClass + "'> </div>";
|
||||
valid++;
|
||||
@ -792,7 +813,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
|
||||
if (showMediaTitle) {
|
||||
|
||||
var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item);
|
||||
var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: options.includeParentInfoInTitle
|
||||
});
|
||||
|
||||
lines.push(name);
|
||||
}
|
||||
@ -964,8 +987,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
if (item.RecordAnyChannel) {
|
||||
lines.push(globalize.translate('sharedcomponents#AllChannels'));
|
||||
}
|
||||
else if (item.ChannelId) {
|
||||
lines.push(item.ChannelName || '');
|
||||
else {
|
||||
lines.push(item.ChannelName || globalize.translate('sharedcomponents#OneChannel'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -974,7 +997,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
lines.push('as ' + item.Role);
|
||||
}
|
||||
else if (item.Type) {
|
||||
lines.push(globalize.translate('core#' + item.Type));
|
||||
lines.push(globalize.translate('sharedcomponents#' + item.Type));
|
||||
} else {
|
||||
lines.push('');
|
||||
}
|
||||
@ -985,7 +1008,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
lines = [];
|
||||
}
|
||||
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, isOuterFooter && options.cardLayout && !options.centerText);
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, isOuterFooter && options.cardLayout && !options.centerText, options.lines);
|
||||
|
||||
if (progressHtml) {
|
||||
html += progressHtml;
|
||||
@ -1041,10 +1064,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
childText += globalize.translate('ValueMinutes', Math.round(minutes));
|
||||
childText += globalize.translate('sharedcomponents#ValueMinutes', Math.round(minutes));
|
||||
|
||||
} else {
|
||||
childText += globalize.translate('ValueMinutes', 0);
|
||||
childText += globalize.translate('sharedcomponents#ValueMinutes', 0);
|
||||
}
|
||||
|
||||
counts.push(childText);
|
||||
@ -1236,7 +1259,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
}
|
||||
|
||||
if (overlayPlayButton && !item.IsPlaceHolder && (item.LocationType !== 'Virtual' || !item.MediaType || item.Type === 'Program') && item.Type !== 'Person' && item.PlayAccess === 'Full') {
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="cardOverlayButton itemAction autoSize" data-action="playmenu" onclick="return false;"><i class="md-icon">play_arrow</i></button>';
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="cardOverlayButton itemAction autoSize" data-action="play" onclick="return false;"><i class="md-icon">play_arrow</i></button>';
|
||||
}
|
||||
if (options.overlayMoreButton) {
|
||||
|
||||
@ -1268,7 +1291,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
cardContentClose = '</button>';
|
||||
}
|
||||
|
||||
if (options.vibrant && imgUrl && !vibrantSwatch) {
|
||||
var vibrantAttributes = options.vibrant && imgUrl && !vibrantSwatch ?
|
||||
(' data-vibrant="' + cardFooterId + '" data-swatch="db"') :
|
||||
'';
|
||||
|
||||
// Don't use the IMG tag with safari because it puts a white border around it
|
||||
if (vibrantAttributes && !browser.safari) {
|
||||
cardImageContainerOpen = '<div class="' + cardImageContainerClass + '">';
|
||||
|
||||
var imgClass = 'cardImage cardImage-img lazy';
|
||||
@ -1279,10 +1307,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
|
||||
imgClass += ' coveredImage-img';
|
||||
}
|
||||
}
|
||||
cardImageContainerOpen += '<img crossOrigin="Anonymous" class="' + imgClass + '" data-vibrant="' + cardFooterId + '" data-swatch="db" data-src="' + imgUrl + '" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />';
|
||||
cardImageContainerOpen += '<img crossOrigin="Anonymous" class="' + imgClass + '"' + vibrantAttributes + ' data-src="' + imgUrl + '" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />';
|
||||
|
||||
} else {
|
||||
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy"' + vibrantAttributes + ' data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
}
|
||||
|
||||
var cardScalableClass = options.cardLayout ? 'cardScalable visualCardBox-cardScalable' : 'cardScalable';
|
||||
|
@ -42,9 +42,6 @@
|
||||
Name: dlg.querySelector('#txtNewCollectionName').value,
|
||||
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
|
||||
//ParentId: getParameterByName('parentId') || LibraryMenu.getTopParentId()
|
||||
|
||||
});
|
||||
|
||||
apiClient.ajax({
|
||||
|
@ -110,30 +110,70 @@
|
||||
return locale;
|
||||
}
|
||||
|
||||
function getOptionList(options) {
|
||||
|
||||
var list = [];
|
||||
|
||||
for (var i in options) {
|
||||
list.push({
|
||||
name: i,
|
||||
value: options[i]
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function toLocaleString(date, options) {
|
||||
options = options || {};
|
||||
|
||||
var currentLocale = getCurrentLocale();
|
||||
|
||||
return currentLocale && toLocaleTimeStringSupportsLocales ?
|
||||
date.toLocaleString(currentLocale, options || {}) :
|
||||
date.toLocaleString();
|
||||
if (currentLocale && toLocaleTimeStringSupportsLocales) {
|
||||
return date.toLocaleString(currentLocale, options);
|
||||
}
|
||||
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
function toLocaleDateString(date, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
var currentLocale = getCurrentLocale();
|
||||
|
||||
return currentLocale && toLocaleTimeStringSupportsLocales ?
|
||||
date.toLocaleDateString(currentLocale, options || {}) :
|
||||
date.toLocaleDateString();
|
||||
if (currentLocale && toLocaleTimeStringSupportsLocales) {
|
||||
return date.toLocaleDateString(currentLocale, options);
|
||||
}
|
||||
|
||||
// This is essentially a hard-coded polyfill
|
||||
var optionList = getOptionList(options);
|
||||
if (optionList.length === 1 && optionList[0].name === 'weekday') {
|
||||
var weekday = [];
|
||||
weekday[0] = "Sun";
|
||||
weekday[1] = "Mon";
|
||||
weekday[2] = "Tue";
|
||||
weekday[3] = "Wed";
|
||||
weekday[4] = "Thu";
|
||||
weekday[5] = "Fri";
|
||||
weekday[6] = "Sat";
|
||||
return weekday[date.getDay()];
|
||||
}
|
||||
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
function toLocaleTimeString(date, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
var currentLocale = getCurrentLocale();
|
||||
|
||||
return currentLocale && toLocaleTimeStringSupportsLocales ?
|
||||
date.toLocaleTimeString(currentLocale, options || {}).toLowerCase() :
|
||||
date.toLocaleTimeString().toLowerCase();
|
||||
if (currentLocale && toLocaleTimeStringSupportsLocales) {
|
||||
return date.toLocaleTimeString(currentLocale, options);
|
||||
}
|
||||
|
||||
return date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
function getDisplayTime(date) {
|
||||
|
40
dashboard-ui/bower_components/emby-webcomponents/deletehelper.js
vendored
Normal file
40
dashboard-ui/bower_components/emby-webcomponents/deletehelper.js
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
define(['connectionManager', 'confirm', 'embyRouter', 'globalize'], function (connectionManager, confirm, embyRouter, globalize) {
|
||||
'use strict';
|
||||
|
||||
function deleteItem(options) {
|
||||
|
||||
var item = options.item;
|
||||
var itemId = item.Id;
|
||||
var parentId = item.SeasonId || item.SeriesId || item.ParentId;
|
||||
var serverId = item.ServerId;
|
||||
|
||||
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
|
||||
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
return confirm({
|
||||
|
||||
title: title,
|
||||
text: msg,
|
||||
confirmText: globalize.translate('sharedcomponents#Delete'),
|
||||
primary: 'cancel'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
return apiClient.deleteItem(itemId).then(function () {
|
||||
|
||||
if (options.navigate) {
|
||||
if (parentId) {
|
||||
embyRouter.showItem(parentId, serverId);
|
||||
} else {
|
||||
embyRouter.goHome();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
deleteItem: deleteItem
|
||||
};
|
||||
});
|
@ -5,20 +5,12 @@
|
||||
|
||||
function enableAnimation() {
|
||||
|
||||
if (browser.animate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edge) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An indication of an older browser
|
||||
if (browser.noFlex) {
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return browser.supportsCssAnimation();
|
||||
}
|
||||
|
||||
function removeCenterFocus(dlg) {
|
||||
@ -246,12 +238,12 @@
|
||||
if (enableAnimation()) {
|
||||
|
||||
var onFinish = function () {
|
||||
dom.removeEventListener(dlg, 'animationend', onFinish, {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
onAnimationFinish();
|
||||
};
|
||||
dom.addEventListener(dlg, 'animationend', onFinish, {
|
||||
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
return;
|
||||
@ -265,6 +257,7 @@
|
||||
if (enableAnimation()) {
|
||||
|
||||
var animated = true;
|
||||
|
||||
switch (dlg.animationConfig.exit.name) {
|
||||
|
||||
case 'fadeout':
|
||||
@ -281,12 +274,12 @@
|
||||
break;
|
||||
}
|
||||
var onFinish = function () {
|
||||
dom.removeEventListener(dlg, 'animationend', onFinish, {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
onAnimationFinish();
|
||||
};
|
||||
dom.addEventListener(dlg, 'animationend', onFinish, {
|
||||
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
|
||||
@ -436,6 +429,7 @@
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
switch (dlg.animationConfig.entry.name) {
|
||||
|
||||
case 'fadein':
|
||||
|
@ -94,12 +94,65 @@ define([], function () {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
var _animationEvent;
|
||||
function whichAnimationEvent() {
|
||||
|
||||
if (_animationEvent) {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var animations = {
|
||||
"animation": "animationend",
|
||||
"OAnimation": "oAnimationEnd",
|
||||
"MozAnimation": "animationend",
|
||||
"WebkitAnimation": "webkitAnimationEnd"
|
||||
};
|
||||
for (t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
}
|
||||
}
|
||||
|
||||
_animationEvent = 'animationend';
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
var _transitionEvent;
|
||||
function whichTransitionEvent() {
|
||||
if (_transitionEvent) {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
"MozTransition": "transitionend",
|
||||
"WebkitTransition": "webkitTransitionEnd"
|
||||
};
|
||||
for (t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
}
|
||||
}
|
||||
|
||||
_transitionEvent = 'transitionend';
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
return {
|
||||
parentWithAttribute: parentWithAttribute,
|
||||
parentWithClass: parentWithClass,
|
||||
parentWithTag: parentWithTag,
|
||||
addEventListener: addEventListenerWithOptions,
|
||||
removeEventListener: removeEventListenerWithOptions,
|
||||
getWindowSize: getWindowSize
|
||||
getWindowSize: getWindowSize,
|
||||
whichTransitionEvent: whichTransitionEvent,
|
||||
whichAnimationEvent: whichAnimationEvent
|
||||
};
|
||||
});
|
@ -15,7 +15,7 @@
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
z-index: 0;
|
||||
padding: 0.7em 0.57em;
|
||||
padding: 1em .7em;
|
||||
font-weight: normal;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
@ -40,6 +40,18 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.emby-button-focusscale {
|
||||
transition: transform 180ms ease-out !important;
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.emby-button-focusscale:focus {
|
||||
transform: scale(1.16);
|
||||
z-index: 1;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.emby-button > i {
|
||||
/* For non-fab buttons that have icons */
|
||||
font-size: 1.36em;
|
||||
@ -50,7 +62,7 @@
|
||||
.fab {
|
||||
display: inline-flex;
|
||||
border-radius: 50%;
|
||||
background-color: #444;
|
||||
background-color: rgba(170,170,190, .4);
|
||||
padding: .6em;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
@ -220,3 +232,14 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.icon-button-focusscale {
|
||||
transition: transform 180ms ease-out !important;
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.icon-button-focusscale:focus {
|
||||
transform: scale(1.3);
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['browser', 'dom', 'css!./emby-button', 'registerElement'], function (browser, dom) {
|
||||
define(['browser', 'dom', 'layoutManager', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
@ -26,7 +26,7 @@
|
||||
btn.appendChild(div);
|
||||
}
|
||||
|
||||
div.addEventListener("animationend", function () {
|
||||
div.addEventListener(dom.whichAnimationEvent(), function () {
|
||||
div.parentNode.removeChild(div);
|
||||
}, false);
|
||||
}
|
||||
@ -73,10 +73,15 @@
|
||||
|
||||
this.classList.add('emby-button');
|
||||
|
||||
if (browser.safari || browser.firefox || browser.noFlex) {
|
||||
// Even though they support flex, it doesn't quite work with button elements
|
||||
if (browser.firefox || browser.safari) {
|
||||
this.classList.add('emby-button-noflex');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('emby-button-focusscale');
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
dom.addEventListener(this, 'keydown', onKeyDown, {
|
||||
passive: true
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['browser', 'dom', 'css!./emby-button', 'registerElement'], function (browser, dom) {
|
||||
define(['browser', 'dom', 'layoutManager', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
btn.appendChild(div);
|
||||
|
||||
div.addEventListener("animationend", function () {
|
||||
div.addEventListener(dom.whichAnimationEvent(), function () {
|
||||
div.parentNode.removeChild(div);
|
||||
}, false);
|
||||
}
|
||||
@ -61,6 +61,10 @@
|
||||
|
||||
this.classList.add('paper-icon-button-light');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('icon-button-focusscale');
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
dom.addEventListener(this, 'keydown', onKeyDown, {
|
||||
passive: true
|
||||
|
@ -2,7 +2,7 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
@ -18,18 +18,7 @@
|
||||
|
||||
.checkboxContainer {
|
||||
margin-bottom: 1.8em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@supports (display: flex) {
|
||||
|
||||
.mdl-checkbox {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.checkboxContainer {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.checkboxContainer-withDescription {
|
||||
|
@ -119,6 +119,8 @@
|
||||
var serverId = el.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
newIndex = Math.max(0, newIndex - 1);
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
|
||||
|
@ -2,7 +2,6 @@
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-bottom: 0 !important;
|
||||
background: none;
|
||||
border: 1px solid #383838;
|
||||
border-width: 0 0 1px 0;
|
||||
/* Prefixed box-sizing rules necessary for older browsers */
|
||||
@ -15,17 +14,21 @@
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
padding: .35em .8em .3em 0;
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emby-select-withoptioncolor {
|
||||
color: inherit;
|
||||
background: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.emby-select option {
|
||||
.emby-select-withoptioncolor > option {
|
||||
color: initial;
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,10 @@
|
||||
inputId++;
|
||||
}
|
||||
|
||||
if (!browser.firefox) {
|
||||
this.classList.add('emby-select-withoptioncolor');
|
||||
}
|
||||
|
||||
this.addEventListener('mousedown', onMouseDown);
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
|
@ -16,7 +16,7 @@ _:-ms-input-placeholder, :root .mdl-slider {
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
padding: 1.5em 0;
|
||||
color: #52B54B;
|
||||
-webkit-align-self: center;
|
||||
-ms-flex-item-align: center;
|
||||
@ -24,6 +24,9 @@ _:-ms-input-placeholder, :root .mdl-slider {
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
display: block;
|
||||
/**************************** Tracks ****************************/
|
||||
/**************************** Thumbs ****************************/
|
||||
/**************************** 0-value ****************************/
|
||||
@ -77,83 +80,85 @@ _:-ms-input-placeholder, :root .mdl-slider {
|
||||
border-radius: 50%;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
transition: border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.mdl-slider::-moz-range-thumb {
|
||||
-moz-appearance: none;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
}
|
||||
.slider-no-webkit-thumb::-webkit-slider-thumb {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.mdl-slider:active::-webkit-slider-thumb {
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
-webkit-transform: scale(1.5);
|
||||
transform: scale(1.5);
|
||||
}
|
||||
.mdl-slider::-moz-range-thumb {
|
||||
-moz-appearance: none;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-slider:active::-moz-range-thumb {
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
.mdl-slider:active::-webkit-slider-thumb {
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
-webkit-transform: scale(1.5);
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.mdl-slider:focus::-webkit-slider-thumb {
|
||||
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
|
||||
}
|
||||
.mdl-slider:active::-moz-range-thumb {
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.mdl-slider:focus::-moz-range-thumb {
|
||||
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
|
||||
}
|
||||
.mdl-slider:focus::-webkit-slider-thumb {
|
||||
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-thumb {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: #52B54B;
|
||||
}
|
||||
.mdl-slider:focus::-moz-range-thumb {
|
||||
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
|
||||
}
|
||||
|
||||
.mdl-slider[disabled]::-ms-thumb {
|
||||
background: gray;
|
||||
}
|
||||
.mdl-slider::-ms-thumb {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: #52B54B;
|
||||
}
|
||||
|
||||
.mdl-slider:disabled:focus::-webkit-slider-thumb, .mdl-slider:disabled:active::-webkit-slider-thumb, .mdl-slider:disabled::-webkit-slider-thumb {
|
||||
-webkit-transform: scale(0.667);
|
||||
transform: scale(0.667);
|
||||
background: rgba(0,0,0, 0.26);
|
||||
}
|
||||
.mdl-slider[disabled]::-ms-thumb {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
.mdl-slider:disabled:focus::-moz-range-thumb, .mdl-slider:disabled:active::-moz-range-thumb, .mdl-slider:disabled::-moz-range-thumb {
|
||||
transform: scale(0.667);
|
||||
background: rgba(0,0,0, 0.26);
|
||||
}
|
||||
.mdl-slider:disabled:focus::-webkit-slider-thumb, .mdl-slider:disabled:active::-webkit-slider-thumb, .mdl-slider:disabled::-webkit-slider-thumb {
|
||||
-webkit-transform: scale(0.667);
|
||||
transform: scale(0.667);
|
||||
background: rgba(0,0,0, 0.26);
|
||||
}
|
||||
|
||||
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-lower {
|
||||
background-color: #444;
|
||||
left: -6px;
|
||||
}
|
||||
.mdl-slider:disabled:focus::-moz-range-thumb, .mdl-slider:disabled:active::-moz-range-thumb, .mdl-slider:disabled::-moz-range-thumb {
|
||||
transform: scale(0.667);
|
||||
background: rgba(0,0,0, 0.26);
|
||||
}
|
||||
|
||||
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-upper {
|
||||
left: 6px;
|
||||
}
|
||||
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-lower {
|
||||
background-color: #444;
|
||||
left: -6px;
|
||||
}
|
||||
|
||||
.mdl-slider:disabled::-ms-fill-lower {
|
||||
margin-right: 6px;
|
||||
background: linear-gradient(to right, transparent, transparent 25px, rgba(30,30,30, 0.7) 25px, rgba(30,30,30, 0.7) 0);
|
||||
}
|
||||
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-upper {
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.mdl-slider:disabled::-ms-fill-upper {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.mdl-slider:disabled::-ms-fill-lower {
|
||||
margin-right: 6px;
|
||||
background: linear-gradient(to right, transparent, transparent 25px, rgba(30,30,30, 0.7) 25px, rgba(30,30,30, 0.7) 0);
|
||||
}
|
||||
|
||||
.mdl-slider:disabled::-ms-fill-upper {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.mdl-slider__ie-container {
|
||||
height: 18px;
|
||||
@ -224,3 +229,7 @@ _:-ms-input-placeholder, :root .mdl-slider {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sliderBubbleText {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['browser', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser) {
|
||||
define(['browser', 'dom', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom) {
|
||||
'use strict';
|
||||
|
||||
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
|
||||
@ -23,20 +23,27 @@
|
||||
if (backgroundLower) {
|
||||
var fraction = (value - range.min) / (range.max - range.min);
|
||||
|
||||
if (browser.noFlex) {
|
||||
backgroundLower.style['-webkit-flex'] = fraction;
|
||||
backgroundUpper.style['-webkit-flex'] = 1 - fraction;
|
||||
backgroundLower.style['-webkit-box-flex'] = fraction;
|
||||
backgroundUpper.style['-webkit-box-flex'] = 1 - fraction;
|
||||
}
|
||||
|
||||
backgroundLower.style.flex = fraction;
|
||||
backgroundUpper.style.flex = 1 - fraction;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateBubble(range, value, bubble) {
|
||||
function updateBubble(range, value, bubble, bubbleText) {
|
||||
|
||||
bubble.style.left = (value - 1) + '%';
|
||||
|
||||
if (range.getBubbleText) {
|
||||
value = range.getBubbleText(value);
|
||||
}
|
||||
bubble.innerHTML = value;
|
||||
bubbleText.innerHTML = value;
|
||||
}
|
||||
|
||||
EmbySliderPrototype.attachedCallback = function () {
|
||||
@ -50,6 +57,10 @@
|
||||
this.classList.add('mdl-slider');
|
||||
this.classList.add('mdl-js-slider');
|
||||
|
||||
if (browser.noFlex) {
|
||||
this.classList.add('slider-no-webkit-thumb');
|
||||
}
|
||||
|
||||
var containerElement = this.parentNode;
|
||||
containerElement.classList.add('mdl-slider__container');
|
||||
|
||||
@ -59,42 +70,70 @@
|
||||
htmlToInsert += '<div class="mdl-slider__background-flex"><div class="mdl-slider__background-lower"></div><div class="mdl-slider__background-upper"></div></div>';
|
||||
}
|
||||
|
||||
htmlToInsert += '<div class="sliderBubble hide"></div>';
|
||||
htmlToInsert += '<div class="sliderBubble hide"><h1 class="sliderBubbleText"></h1></div>';
|
||||
|
||||
containerElement.insertAdjacentHTML('beforeend', htmlToInsert);
|
||||
|
||||
var backgroundLower = containerElement.querySelector('.mdl-slider__background-lower');
|
||||
var backgroundUpper = containerElement.querySelector('.mdl-slider__background-upper');
|
||||
var sliderBubble = containerElement.querySelector('.sliderBubble');
|
||||
var sliderBubbleText = containerElement.querySelector('.sliderBubbleText');
|
||||
|
||||
var hasHideClass = sliderBubble.classList.contains('hide');
|
||||
|
||||
this.addEventListener('input', function (e) {
|
||||
dom.addEventListener(this, 'input', function (e) {
|
||||
this.dragging = true;
|
||||
});
|
||||
this.addEventListener('change', function () {
|
||||
this.dragging = false;
|
||||
updateValues(this, backgroundLower, backgroundUpper);
|
||||
});
|
||||
|
||||
this.addEventListener('mousemove', function (e) {
|
||||
|
||||
var rect = this.getBoundingClientRect();
|
||||
var clientX = e.clientX;
|
||||
var bubbleValue = (clientX - rect.left) / rect.width;
|
||||
bubbleValue *= 100;
|
||||
updateBubble(this, Math.round(bubbleValue), sliderBubble);
|
||||
updateBubble(this, this.value, sliderBubble, sliderBubbleText);
|
||||
|
||||
if (hasHideClass) {
|
||||
sliderBubble.classList.remove('hide');
|
||||
hasHideClass = false;
|
||||
}
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
this.addEventListener('mouseleave', function () {
|
||||
|
||||
dom.addEventListener(this, 'change', function () {
|
||||
this.dragging = false;
|
||||
updateValues(this, backgroundLower, backgroundUpper);
|
||||
|
||||
sliderBubble.classList.add('hide');
|
||||
hasHideClass = true;
|
||||
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
// In firefox this feature disrupts the ability to move the slider
|
||||
if (!browser.firefox) {
|
||||
dom.addEventListener(this, 'mousemove', function (e) {
|
||||
|
||||
if (!this.dragging) {
|
||||
var rect = this.getBoundingClientRect();
|
||||
var clientX = e.clientX;
|
||||
var bubbleValue = (clientX - rect.left) / rect.width;
|
||||
bubbleValue *= 100;
|
||||
updateBubble(this, Math.round(bubbleValue), sliderBubble, sliderBubbleText);
|
||||
|
||||
if (hasHideClass) {
|
||||
sliderBubble.classList.remove('hide');
|
||||
hasHideClass = false;
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'mouseleave', function () {
|
||||
sliderBubble.classList.add('hide');
|
||||
hasHideClass = true;
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!supportsNativeProgressStyle) {
|
||||
|
||||
if (supportsValueSetOverride) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
width: auto;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
color: #aaa !important;
|
||||
color: #aaa;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
@ -17,7 +17,7 @@
|
||||
transition: none !important;
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold !important;
|
||||
font-weight: bold;
|
||||
height: auto;
|
||||
min-width: initial;
|
||||
line-height: initial;
|
||||
@ -26,11 +26,11 @@
|
||||
}
|
||||
|
||||
.emby-tab-button:focus {
|
||||
font-weight: bold !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.emby-tab-button-active {
|
||||
color: #52B54B !important;
|
||||
color: #52B54B;
|
||||
border-color: #52B54B;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['dom', 'scroller', 'browser', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser) {
|
||||
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyTabs = Object.create(HTMLDivElement.prototype);
|
||||
@ -97,6 +97,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusCallback(tabs, e) {
|
||||
return function () {
|
||||
onClick.call(tabs, e);
|
||||
};
|
||||
}
|
||||
|
||||
function onFocus(e) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
||||
if (this.focusTimeout) {
|
||||
clearTimeout(this.focusTimeout);
|
||||
}
|
||||
this.focusTimeout = setTimeout(getFocusCallback(this, e), 700);
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var tabs = this;
|
||||
@ -204,14 +221,37 @@
|
||||
return;
|
||||
}
|
||||
this.classList.add('emby-tabs');
|
||||
this.classList.add('focusable');
|
||||
|
||||
dom.addEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'focus', onFocus, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
|
||||
initSelectionBar(this);
|
||||
};
|
||||
|
||||
EmbyTabs.focus = function () {
|
||||
|
||||
var selected = this.querySelector('.' + activeButtonClass);
|
||||
|
||||
if (selected) {
|
||||
focusManager.focus(selected);
|
||||
} else {
|
||||
focusManager.autoFocus(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.refresh = function () {
|
||||
|
||||
if (this.scroller) {
|
||||
this.scroller.reload();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.attachedCallback = function () {
|
||||
|
||||
initScroller(this);
|
||||
@ -236,6 +276,10 @@
|
||||
dom.removeEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'focus', onFocus, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
this.selectionBar = null;
|
||||
};
|
||||
|
||||
|
@ -304,10 +304,12 @@ define(['dom'], function (dom) {
|
||||
var nearestElement = nearest[0].node;
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && activeElement) {
|
||||
if (dom.parentWithClass(activeElement, 'focusable') !== nearestElementFocusableParent) {
|
||||
nearestElement = nearestElementFocusableParent;
|
||||
if (activeElement) {
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
|
||||
if (focusableContainer !== nearestElementFocusableParent) {
|
||||
nearestElement = nearestElementFocusableParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
focus(nearestElement);
|
||||
|
@ -51,7 +51,8 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: block;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
padding: 1.25em 1em;
|
||||
/* Without this emby-checkbox is able to appear on top */
|
||||
z-index: 1;
|
||||
@ -60,16 +61,9 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@supports (display: flex) {
|
||||
|
||||
.formDialogFooter {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.formDialogFooter-flex {
|
||||
position: static;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formDialogFooterItem {
|
||||
|
@ -185,7 +185,13 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana
|
||||
|
||||
function translateKeyFromModule(key, module) {
|
||||
|
||||
return getDictionary(module)[key] || key;
|
||||
var dictionary = getDictionary(module);
|
||||
|
||||
if (!dictionary) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return dictionary[key] || key;
|
||||
}
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
|
@ -1,106 +0,0 @@
|
||||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
|
||||
function save(context, options) {
|
||||
|
||||
var categories = [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function load(context, options) {
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function showEditor(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
require(['text!./guide-categories.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
|
||||
settingsChanged = true;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve(options);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${Categories}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<form class="dialogContentInner dialog-content-centered" style="padding-top:2em;">
|
||||
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="movies" />
|
||||
<span>${Movies}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="sports" />
|
||||
<span>${Sports}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="kids" />
|
||||
<span>${Kids}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="news" />
|
||||
<span>${News}</span>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,6 +1,42 @@
|
||||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
|
||||
function saveCategories(context, options) {
|
||||
|
||||
var categories = [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
|
||||
var i, length;
|
||||
@ -65,7 +101,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showEditor() {
|
||||
function showEditor(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
@ -106,6 +142,7 @@
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
@ -123,6 +160,7 @@
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
|
@ -40,8 +40,29 @@
|
||||
</div>
|
||||
<br />
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds" />
|
||||
<input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds"/>
|
||||
<span>${EnableColorCodedBackgrounds}</span>
|
||||
</label>
|
||||
|
||||
<h3 class="checkboxListLabel">${Categories}</h3>
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="movies" />
|
||||
<span>${Movies}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="sports" />
|
||||
<span>${Sports}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="kids" />
|
||||
<span>${Kids}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="news" />
|
||||
<span>${News}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
@ -7,9 +7,18 @@
|
||||
.tvGuideHeader {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
padding-left: 3.4em;
|
||||
}
|
||||
|
||||
.guideHeaderDateSelection {
|
||||
font-size: 86%;
|
||||
padding: .4em 0;
|
||||
}
|
||||
|
||||
.guideHeaderTimeslots {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tvProgramSectionHeader {
|
||||
@ -38,6 +47,7 @@
|
||||
|
||||
.channelTimeslotHeader {
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timeslotHeaders {
|
||||
@ -49,6 +59,7 @@
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
@ -77,7 +88,7 @@
|
||||
|
||||
.currentTimeIndicatorArrowContainer {
|
||||
position: absolute;
|
||||
bottom: -1.3vh;
|
||||
bottom: -1vh;
|
||||
width: 100%;
|
||||
color: #52B54B;
|
||||
margin-left: .65vh;
|
||||
@ -91,11 +102,11 @@
|
||||
}
|
||||
|
||||
.currentTimeIndicatorArrow {
|
||||
width: 4vh;
|
||||
height: 4vh;
|
||||
font-size: 4vh;
|
||||
width: 3vh;
|
||||
height: 3vh;
|
||||
font-size: 3vh;
|
||||
color: #52B54B;
|
||||
margin-left: -2vh;
|
||||
margin-left: -1.5vh;
|
||||
}
|
||||
|
||||
.channelPrograms, .timeslotHeadersInner {
|
||||
@ -171,29 +182,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btnSelectDate {
|
||||
padding-left: .5em;
|
||||
text-transform: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.btnSelectDateContent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.guideDateText {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
@media all and (min-width: 1600px) {
|
||||
|
||||
.guideDateText {
|
||||
font-size: 92%;
|
||||
}
|
||||
}
|
||||
|
||||
.btnGuideViewSettings {
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
@ -203,13 +191,6 @@
|
||||
font-size: 1.5em !important;
|
||||
}
|
||||
|
||||
@media all and (max-width: 1280px) {
|
||||
|
||||
.btnGuideViewSettings {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.selectDateIcon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@ -258,11 +239,12 @@
|
||||
}
|
||||
|
||||
.timeslotHeader, .channelTimeslotHeader {
|
||||
height: 3em;
|
||||
height: 2.2em;
|
||||
}
|
||||
|
||||
.programGrid {
|
||||
padding-bottom: 4px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.timeslotHeader {
|
||||
@ -347,7 +329,7 @@
|
||||
}
|
||||
|
||||
.programTextIcon-tv {
|
||||
font-size: .7em;
|
||||
font-size: .6em;
|
||||
}
|
||||
|
||||
.guideChannelNumber {
|
||||
@ -384,29 +366,6 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btnCategories {
|
||||
margin: 0 .3em 0 .5em !important;
|
||||
padding: 0 !important;
|
||||
flex-shrink: 0;
|
||||
background: rgba(40, 40, 40, .9);
|
||||
border-radius: 0 !important;
|
||||
width: 2.6em;
|
||||
font-weight: normal !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btnCategoriesText {
|
||||
transform: rotate(90deg);
|
||||
text-transform: uppercase;
|
||||
transform-origin: left;
|
||||
margin-left: 1.2em;
|
||||
letter-spacing: .25em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin-top: 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.channelList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -416,11 +375,11 @@
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.programCell, .channelHeaderCell, .btnSelectDate {
|
||||
.programCell, .channelHeaderCell {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.programCell:focus, .channelHeaderCell:focus, .btnSelectDate:focus {
|
||||
.programCell:focus, .channelHeaderCell:focus {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
@ -433,25 +392,6 @@
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.visibleGuideScroller::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.visibleGuideScroller::-webkit-scrollbar-button:start:decrement,
|
||||
.visibleGuideScroller::-webkit-scrollbar-button:end:increment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.visibleGuideScroller::-webkit-scrollbar-track-piece {
|
||||
background-color: #3b3b3b;
|
||||
}
|
||||
|
||||
.visibleGuideScroller::-webkit-scrollbar-thumb:vertical, .visibleGuideScroller::-webkit-scrollbar-thumb:horizontal {
|
||||
-webkit-border-radius: 2px;
|
||||
background: #888 no-repeat center;
|
||||
}
|
||||
|
||||
.guideOptions {
|
||||
color: #eee;
|
||||
flex-shrink: 0;
|
||||
@ -464,8 +404,54 @@
|
||||
.tvGuideHeader {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btnCategories {
|
||||
display: none;
|
||||
.guideRequiresUnlock {
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.noRubberBanding {
|
||||
/* This is needed to combat the rubber banding in iOS */
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.guideDateTabsSlider {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.guide-date-tab-button {
|
||||
font-weight: 500 !important;
|
||||
color: inherit !important;
|
||||
padding-top: .3em !important;
|
||||
padding-bottom: .3em !important;
|
||||
opacity: .25;
|
||||
}
|
||||
|
||||
.guide-date-tab-button.emby-tab-button-active {
|
||||
color: #52B54B !important;
|
||||
border-color: transparent !important;
|
||||
opacity: 1;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.guide-date-tab-button:focus {
|
||||
color: #52B54B !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.layout-tv .guide-date-tab-button:focus {
|
||||
background-color: #52B54B !important;
|
||||
border-radius: .25em !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 1200px) {
|
||||
|
||||
.guide-date-tab-button {
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,10 @@
|
||||
define(['require', 'browser', 'globalize', 'connectionManager', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'registrationServices', 'dom', 'clearButtonStyle', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-button', 'paper-icon-button-light'], function (require, browser, globalize, connectionManager, serverNotifications, loading, datetime, focusManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, registrationServices, dom) {
|
||||
define(['require', 'browser', 'globalize', 'connectionManager', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'registrationServices', 'dom', 'clearButtonStyle', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-button', 'paper-icon-button-light', 'emby-tabs'], function (require, browser, globalize, connectionManager, serverNotifications, loading, datetime, focusManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, registrationServices, dom) {
|
||||
'use strict';
|
||||
|
||||
function showViewSettings(instance) {
|
||||
|
||||
require(['guide-settings-dialog'], function (guideSettingsDialog) {
|
||||
guideSettingsDialog.show().then(function () {
|
||||
instance.refresh();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showCategoryOptions(instance) {
|
||||
|
||||
require(['guide-categories-dialog'], function (guideCategoriesDialog) {
|
||||
guideCategoriesDialog.show(instance.categoryOptions).then(function (categoryOptions) {
|
||||
|
||||
instance.categoryOptions = categoryOptions;
|
||||
guideSettingsDialog.show(instance.categoryOptions).then(function () {
|
||||
instance.refresh();
|
||||
});
|
||||
});
|
||||
@ -38,15 +27,31 @@
|
||||
var currentDate;
|
||||
var currentStartIndex = 0;
|
||||
var currentChannelLimit = 0;
|
||||
var autoRefreshInterval;
|
||||
|
||||
self.refresh = function () {
|
||||
|
||||
currentDate = null;
|
||||
reloadPage(options.element);
|
||||
restartAutoRefresh();
|
||||
};
|
||||
|
||||
self.pause = function () {
|
||||
stopAutoRefresh();
|
||||
};
|
||||
|
||||
self.resume = function (refreshData) {
|
||||
if (refreshData) {
|
||||
self.refresh();
|
||||
} else {
|
||||
restartAutoRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
self.destroy = function () {
|
||||
|
||||
stopAutoRefresh();
|
||||
|
||||
events.off(serverNotifications, 'TimerCreated', onTimerCreated);
|
||||
events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated);
|
||||
events.off(serverNotifications, 'TimerCancelled', onTimerCancelled);
|
||||
@ -58,6 +63,24 @@
|
||||
items = {};
|
||||
};
|
||||
|
||||
function restartAutoRefresh() {
|
||||
|
||||
stopAutoRefresh();
|
||||
|
||||
var intervalMs = 60000 * 15; // (minutes)
|
||||
|
||||
autoRefreshInterval = setInterval(function () {
|
||||
self.refresh();
|
||||
}, intervalMs);
|
||||
}
|
||||
|
||||
function stopAutoRefresh() {
|
||||
if (autoRefreshInterval) {
|
||||
clearInterval(autoRefreshInterval);
|
||||
autoRefreshInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeDateToTimeslot(date) {
|
||||
|
||||
var minutesOffset = date.getMinutes() - cellCurationMinutes;
|
||||
@ -152,7 +175,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function reloadGuide(context, newStartDate) {
|
||||
function reloadGuide(context, newStartDate, focusProgramOnRender) {
|
||||
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
|
||||
@ -211,8 +234,8 @@
|
||||
channelQuery.SortBy = "DatePlayed";
|
||||
channelQuery.SortOrder = "Descending";
|
||||
} else {
|
||||
channelQuery.SortBy = "SortName";
|
||||
channelQuery.SortOrder = "Ascending";
|
||||
channelQuery.SortBy = null;
|
||||
channelQuery.SortOrder = null;
|
||||
}
|
||||
|
||||
var date = newStartDate;
|
||||
@ -267,7 +290,7 @@
|
||||
|
||||
}).then(function (programsResult) {
|
||||
|
||||
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient);
|
||||
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient, focusProgramOnRender);
|
||||
|
||||
hideLoading();
|
||||
|
||||
@ -482,7 +505,7 @@
|
||||
timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"';
|
||||
}
|
||||
|
||||
html += '<button data-action="' + clickAction + '"' + timerAttributes + ' data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
|
||||
html += '<button data-action="' + clickAction + '"' + timerAttributes + ' data-channelid="' + program.ChannelId + '" data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
|
||||
|
||||
if (displayInnerContent) {
|
||||
var guideProgramNameClass = "guideProgramName";
|
||||
@ -605,7 +628,7 @@
|
||||
imageLoader.lazyChildren(channelList);
|
||||
}
|
||||
|
||||
function renderGuide(context, date, channels, programs, apiClient) {
|
||||
function renderGuide(context, date, channels, programs, apiClient, focusProgramOnRender) {
|
||||
|
||||
//var list = [];
|
||||
//channels.forEach(function(i) {
|
||||
@ -663,7 +686,7 @@
|
||||
items = {};
|
||||
renderPrograms(context, date, channels, programs);
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (focusProgramOnRender) {
|
||||
|
||||
var focusElem;
|
||||
if (itemId) {
|
||||
@ -723,21 +746,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
function changeDate(page, date) {
|
||||
function changeDate(page, date, focusProgramOnRender) {
|
||||
|
||||
clearCurrentTimeUpdateInterval();
|
||||
|
||||
var newStartDate = normalizeDateToTimeslot(date);
|
||||
currentDate = newStartDate;
|
||||
|
||||
reloadGuide(page, newStartDate);
|
||||
|
||||
var dateText = datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' });
|
||||
|
||||
page.querySelector('.guideDateText').innerHTML = dateText;
|
||||
reloadGuide(page, newStartDate, focusProgramOnRender);
|
||||
}
|
||||
|
||||
var dateOptions = [];
|
||||
function getDateTabText(date, isActive, tabIndex) {
|
||||
|
||||
var cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button';
|
||||
|
||||
var html = '<button is="emby-button" class="' + cssClass + '" data-index="' + tabIndex + '" data-date="' + date.getTime() + '">';
|
||||
var tabText = datetime.toLocaleDateString(date, { weekday: 'short' });
|
||||
|
||||
tabText += '<br/>';
|
||||
tabText += date.getDate();
|
||||
html += '<div class="emby-button-foreground">' + tabText + '</div>';
|
||||
html += '</button>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function setDateRange(page, guideInfo) {
|
||||
|
||||
@ -756,18 +788,8 @@
|
||||
|
||||
start = new Date(Math.max(today, start));
|
||||
|
||||
dateOptions = [];
|
||||
|
||||
while (start <= end) {
|
||||
|
||||
dateOptions.push({
|
||||
name: datetime.toLocaleDateString(start, { weekday: 'long', month: 'long', day: 'numeric' }),
|
||||
id: start.getTime()
|
||||
});
|
||||
|
||||
start.setDate(start.getDate() + 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
}
|
||||
var dateTabsHtml = '';
|
||||
var tabIndex = 0;
|
||||
|
||||
var date = new Date();
|
||||
|
||||
@ -775,7 +797,21 @@
|
||||
date.setTime(currentDate.getTime());
|
||||
}
|
||||
|
||||
changeDate(page, date);
|
||||
while (start <= end) {
|
||||
|
||||
var isActive = date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear();
|
||||
|
||||
dateTabsHtml += getDateTabText(start, isActive, tabIndex);
|
||||
|
||||
start.setDate(start.getDate() + 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
tabIndex++;
|
||||
}
|
||||
|
||||
page.querySelector('.emby-tabs-slider').innerHTML = dateTabsHtml;
|
||||
page.querySelector('.guideDateTabs').refresh();
|
||||
|
||||
changeDate(page, date, layoutManager.tv);
|
||||
}
|
||||
|
||||
function reloadPage(page) {
|
||||
@ -790,36 +826,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
function selectDate(page) {
|
||||
|
||||
var selectedDate = currentDate || new Date();
|
||||
dateOptions.forEach(function (d) {
|
||||
d.selected = new Date(d.id).getDate() === selectedDate.getDate();
|
||||
});
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
|
||||
actionsheet.show({
|
||||
items: dateOptions,
|
||||
title: globalize.translate('sharedcomponents#HeaderSelectDate'),
|
||||
callback: function (id) {
|
||||
|
||||
var date = new Date();
|
||||
date.setTime(parseInt(id));
|
||||
changeDate(page, date);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function setScrollEvents(view, enabled) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
|
||||
var fn = enabled ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](view.querySelector('.smoothScrollY'), false);
|
||||
scrollHelper.centerFocus[fn](view.querySelector('.guideVerticalScroller'), false);
|
||||
scrollHelper.centerFocus[fn](view.querySelector('.programGrid'), true);
|
||||
});
|
||||
}
|
||||
@ -903,9 +916,9 @@
|
||||
context.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
if (layoutManager.desktop) {
|
||||
var visibleGuideScrollers = context.querySelectorAll('.guideScroller');
|
||||
for (var i = 0, length = visibleGuideScrollers.length; i < length; i++) {
|
||||
visibleGuideScrollers[i].classList.add('visibleGuideScroller');
|
||||
var guideScrollers = context.querySelectorAll('.guideScroller');
|
||||
for (var i = 0, length = guideScrollers.length; i < length; i++) {
|
||||
guideScrollers[i].classList.add('darkScroller');
|
||||
}
|
||||
}
|
||||
|
||||
@ -914,6 +927,16 @@
|
||||
|
||||
programGrid.addEventListener('focus', onProgramGridFocus, true);
|
||||
|
||||
if (browser.iOS || browser.osx) {
|
||||
context.querySelector('.channelsContainer').classList.add('noRubberBanding');
|
||||
|
||||
var programGridContainer = context.querySelector('.programGridContainer');
|
||||
|
||||
programGridContainer.classList.add('noRubberBanding');
|
||||
programGridContainer.classList.remove('smoothScrollX');
|
||||
programGridContainer.classList.add('hiddenScrollX');
|
||||
}
|
||||
|
||||
dom.addEventListener(programGrid, 'scroll', function (e) {
|
||||
onProgramGridScroll(context, this, timeslotHeaders);
|
||||
}, {
|
||||
@ -926,31 +949,37 @@
|
||||
passive: true
|
||||
});
|
||||
|
||||
context.querySelector('.btnSelectDate').addEventListener('click', function () {
|
||||
selectDate(context);
|
||||
});
|
||||
|
||||
context.querySelector('.btnUnlockGuide').addEventListener('click', function () {
|
||||
currentStartIndex = 0;
|
||||
reloadPage(context);
|
||||
restartAutoRefresh();
|
||||
});
|
||||
|
||||
context.querySelector('.btnNextPage').addEventListener('click', function () {
|
||||
currentStartIndex += currentChannelLimit;
|
||||
reloadPage(context);
|
||||
restartAutoRefresh();
|
||||
});
|
||||
|
||||
context.querySelector('.btnPreviousPage').addEventListener('click', function () {
|
||||
currentStartIndex = Math.max(currentStartIndex - currentChannelLimit, 0);
|
||||
reloadPage(context);
|
||||
restartAutoRefresh();
|
||||
});
|
||||
|
||||
context.querySelector('.btnGuideViewSettings').addEventListener('click', function () {
|
||||
showViewSettings(self);
|
||||
restartAutoRefresh();
|
||||
});
|
||||
|
||||
context.querySelector('.btnCategories').addEventListener('click', function () {
|
||||
showCategoryOptions(self);
|
||||
context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
|
||||
|
||||
var tabButton = e.target.querySelectorAll('.guide-date-tab-button')[parseInt(e.detail.selectedTabIndex)];
|
||||
if (tabButton) {
|
||||
var date = new Date();
|
||||
date.setTime(parseInt(tabButton.getAttribute('data-date')));
|
||||
changeDate(context, date, false);
|
||||
}
|
||||
});
|
||||
|
||||
context.classList.add('tvguide');
|
||||
|
@ -1,36 +1,33 @@
|
||||
<div class="tvGuideHeader">
|
||||
<div class="channelTimeslotHeader">
|
||||
<button is="emby-button" type="button" class="btnSelectDate block button-flat" style="color:inherit;">
|
||||
<div class="btnSelectDateContent">
|
||||
<div class="guideDateText">
|
||||
</div>
|
||||
<i class="md-icon selectDateIcon"></i>
|
||||
|
||||
<div class="guideHeaderDateSelection">
|
||||
<div is="emby-tabs" class="guideDateTabs" data-selectionbar="false">
|
||||
<div class="emby-tabs-slider guideDateTabsSlider">
|
||||
</div>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
|
||||
<i class="md-icon btnGuideViewSettingsIcon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeslotHeaders smoothScrollX guideScroller" style="scroll-behavior: auto;"></div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex;flex-grow:1;overflow:hidden;">
|
||||
|
||||
<button is="emby-button" type="button" class="btnCategories">
|
||||
<div class="btnCategoriesText">${Categories}</div>
|
||||
</button>
|
||||
<div class="smoothScrollY guideVerticalScroller programContainer guideScroller" style="flex-grow: 1;">
|
||||
|
||||
<div class="channelsContainer">
|
||||
<div class="channelList"></div>
|
||||
</div>
|
||||
|
||||
<div class="programGridContainer programGrid smoothScrollX guideScroller" style="white-space: nowrap;">
|
||||
<div class="guideHeaderTimeslots">
|
||||
<div class="channelTimeslotHeader">
|
||||
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
|
||||
<i class="md-icon btnGuideViewSettingsIcon"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="timeslotHeaders smoothScrollX guideScroller" style="scroll-behavior: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="guideRequiresUnlock readOnlyContent hide" style="margin: 1em auto; text-align: center; padding: 1em; flex-shrink: 0;">
|
||||
<div class="smoothScrollY guideVerticalScroller programContainer guideScroller">
|
||||
|
||||
<div class="channelsContainer">
|
||||
<div class="channelList"></div>
|
||||
</div>
|
||||
|
||||
<div class="programGridContainer programGrid smoothScrollX guideScroller" style="white-space: nowrap;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="guideRequiresUnlock hide">
|
||||
<p class="unlockText"></p>
|
||||
<button is="emby-button" type="button" class="raised button-submit block btnUnlockGuide">
|
||||
<span>${UnlockGuide}</span>
|
||||
|
323
dashboard-ui/bower_components/emby-webcomponents/idb.js
vendored
Normal file
323
dashboard-ui/bower_components/emby-webcomponents/idb.js
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
// from https://github.com/jakearchibald/idb
|
||||
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
function toArray(arr) {
|
||||
return Array.prototype.slice.call(arr);
|
||||
}
|
||||
|
||||
function promisifyRequest(request) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
request.onsuccess = function () {
|
||||
resolve(request.result);
|
||||
};
|
||||
|
||||
request.onerror = function () {
|
||||
reject(request.error);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function promisifyRequestCall(obj, method, args) {
|
||||
var request;
|
||||
var p = new Promise(function (resolve, reject) {
|
||||
request = obj[method].apply(obj, args);
|
||||
promisifyRequest(request).then(resolve, reject);
|
||||
});
|
||||
|
||||
p.request = request;
|
||||
return p;
|
||||
}
|
||||
|
||||
function promisifyCursorRequestCall(obj, method, args) {
|
||||
var p = promisifyRequestCall(obj, method, args);
|
||||
return p.then(function (value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
return new Cursor(value, p.request);
|
||||
});
|
||||
}
|
||||
|
||||
function proxyProperties(ProxyClass, targetProp, properties) {
|
||||
properties.forEach(function (prop) {
|
||||
Object.defineProperty(ProxyClass.prototype, prop, {
|
||||
get: function () {
|
||||
return this[targetProp][prop];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function proxyRequestMethods(ProxyClass, targetProp, Constructor, properties) {
|
||||
properties.forEach(function (prop) {
|
||||
if (!(prop in Constructor.prototype)) {
|
||||
return;
|
||||
}
|
||||
ProxyClass.prototype[prop] = function () {
|
||||
return promisifyRequestCall(this[targetProp], prop, arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function proxyMethods(ProxyClass, targetProp, Constructor, properties) {
|
||||
properties.forEach(function (prop) {
|
||||
if (!(prop in Constructor.prototype)) {
|
||||
return;
|
||||
}
|
||||
ProxyClass.prototype[prop] = function () {
|
||||
return this[targetProp][prop].apply(this[targetProp], arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function proxyCursorRequestMethods(ProxyClass, targetProp, Constructor, properties) {
|
||||
properties.forEach(function (prop) {
|
||||
if (!(prop in Constructor.prototype)) {
|
||||
return;
|
||||
}
|
||||
ProxyClass.prototype[prop] = function () {
|
||||
return promisifyCursorRequestCall(this[targetProp], prop, arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function Index(index) {
|
||||
this._index = index;
|
||||
}
|
||||
|
||||
proxyProperties(Index, '_index', [
|
||||
'name',
|
||||
'keyPath',
|
||||
'multiEntry',
|
||||
'unique'
|
||||
]);
|
||||
|
||||
proxyRequestMethods(Index, '_index', IDBIndex, [
|
||||
'get',
|
||||
'getKey',
|
||||
'getAll',
|
||||
'getAllKeys',
|
||||
'count'
|
||||
]);
|
||||
|
||||
proxyCursorRequestMethods(Index, '_index', IDBIndex, [
|
||||
'openCursor',
|
||||
'openKeyCursor'
|
||||
]);
|
||||
|
||||
function Cursor(cursor, request) {
|
||||
this._cursor = cursor;
|
||||
this._request = request;
|
||||
}
|
||||
|
||||
proxyProperties(Cursor, '_cursor', [
|
||||
'direction',
|
||||
'key',
|
||||
'primaryKey',
|
||||
'value'
|
||||
]);
|
||||
|
||||
proxyRequestMethods(Cursor, '_cursor', IDBCursor, [
|
||||
'update',
|
||||
'delete'
|
||||
]);
|
||||
|
||||
// proxy 'next' methods
|
||||
['advance', 'continue', 'continuePrimaryKey'].forEach(function (methodName) {
|
||||
if (!(methodName in IDBCursor.prototype)) {
|
||||
return;
|
||||
}
|
||||
Cursor.prototype[methodName] = function () {
|
||||
var cursor = this;
|
||||
var args = arguments;
|
||||
return Promise.resolve().then(function () {
|
||||
cursor._cursor[methodName].apply(cursor._cursor, args);
|
||||
return promisifyRequest(cursor._request).then(function (value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
return new Cursor(value, cursor._request);
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
function ObjectStore(store) {
|
||||
this._store = store;
|
||||
}
|
||||
|
||||
ObjectStore.prototype.createIndex = function () {
|
||||
return new Index(this._store.createIndex.apply(this._store, arguments));
|
||||
};
|
||||
|
||||
ObjectStore.prototype.index = function () {
|
||||
return new Index(this._store.index.apply(this._store, arguments));
|
||||
};
|
||||
|
||||
proxyProperties(ObjectStore, '_store', [
|
||||
'name',
|
||||
'keyPath',
|
||||
'indexNames',
|
||||
'autoIncrement'
|
||||
]);
|
||||
|
||||
proxyRequestMethods(ObjectStore, '_store', IDBObjectStore, [
|
||||
'put',
|
||||
'add',
|
||||
'delete',
|
||||
'clear',
|
||||
'get',
|
||||
'getAll',
|
||||
'getAllKeys',
|
||||
'count'
|
||||
]);
|
||||
|
||||
proxyCursorRequestMethods(ObjectStore, '_store', IDBObjectStore, [
|
||||
'openCursor',
|
||||
'openKeyCursor'
|
||||
]);
|
||||
|
||||
proxyMethods(ObjectStore, '_store', IDBObjectStore, [
|
||||
'deleteIndex'
|
||||
]);
|
||||
|
||||
function Transaction(idbTransaction) {
|
||||
this._tx = idbTransaction;
|
||||
this.complete = new Promise(function (resolve, reject) {
|
||||
idbTransaction.oncomplete = function () {
|
||||
resolve();
|
||||
};
|
||||
idbTransaction.onerror = function () {
|
||||
reject(idbTransaction.error);
|
||||
};
|
||||
idbTransaction.onabort = function () {
|
||||
reject(idbTransaction.error);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Transaction.prototype.objectStore = function () {
|
||||
return new ObjectStore(this._tx.objectStore.apply(this._tx, arguments));
|
||||
};
|
||||
|
||||
proxyProperties(Transaction, '_tx', [
|
||||
'objectStoreNames',
|
||||
'mode'
|
||||
]);
|
||||
|
||||
proxyMethods(Transaction, '_tx', IDBTransaction, [
|
||||
'abort'
|
||||
]);
|
||||
|
||||
function UpgradeDB(db, oldVersion, transaction) {
|
||||
this._db = db;
|
||||
this.oldVersion = oldVersion;
|
||||
this.transaction = new Transaction(transaction);
|
||||
}
|
||||
|
||||
UpgradeDB.prototype.createObjectStore = function () {
|
||||
return new ObjectStore(this._db.createObjectStore.apply(this._db, arguments));
|
||||
};
|
||||
|
||||
proxyProperties(UpgradeDB, '_db', [
|
||||
'name',
|
||||
'version',
|
||||
'objectStoreNames'
|
||||
]);
|
||||
|
||||
proxyMethods(UpgradeDB, '_db', IDBDatabase, [
|
||||
'deleteObjectStore',
|
||||
'close'
|
||||
]);
|
||||
|
||||
function DB(db) {
|
||||
this._db = db;
|
||||
}
|
||||
|
||||
DB.prototype.transaction = function () {
|
||||
return new Transaction(this._db.transaction.apply(this._db, arguments));
|
||||
};
|
||||
|
||||
proxyProperties(DB, '_db', [
|
||||
'name',
|
||||
'version',
|
||||
'objectStoreNames'
|
||||
]);
|
||||
|
||||
proxyMethods(DB, '_db', IDBDatabase, [
|
||||
'close'
|
||||
]);
|
||||
|
||||
// Add cursor iterators
|
||||
// TODO: remove this once browsers do the right thing with promises
|
||||
['openCursor', 'openKeyCursor'].forEach(function (funcName) {
|
||||
[ObjectStore, Index].forEach(function (Constructor) {
|
||||
Constructor.prototype[funcName.replace('open', 'iterate')] = function () {
|
||||
var args = toArray(arguments);
|
||||
var callback = args[args.length - 1];
|
||||
var nativeObject = this._store || this._index;
|
||||
var request = nativeObject[funcName].apply(nativeObject, args.slice(0, -1));
|
||||
request.onsuccess = function () {
|
||||
callback(request.result);
|
||||
};
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// polyfill getAll
|
||||
[Index, ObjectStore].forEach(function (Constructor) {
|
||||
if (Constructor.prototype.getAll) {
|
||||
return;
|
||||
}
|
||||
Constructor.prototype.getAll = function (query, count) {
|
||||
var instance = this;
|
||||
var items = [];
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
instance.iterateCursor(query, function (cursor) {
|
||||
if (!cursor) {
|
||||
resolve(items);
|
||||
return;
|
||||
}
|
||||
items.push(cursor.value);
|
||||
|
||||
if (count !== undefined && items.length === count) {
|
||||
resolve(items);
|
||||
return;
|
||||
}
|
||||
cursor.continue();
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
var exp = {
|
||||
open: function (name, version, upgradeCallback) {
|
||||
var p = promisifyRequestCall(indexedDB, 'open', [name, version]);
|
||||
var request = p.request;
|
||||
|
||||
request.onupgradeneeded = function (event) {
|
||||
if (upgradeCallback) {
|
||||
upgradeCallback(new UpgradeDB(request.result, event.oldVersion, request.transaction));
|
||||
}
|
||||
};
|
||||
|
||||
return p.then(function (db) {
|
||||
return new DB(db);
|
||||
});
|
||||
},
|
||||
delete: function (name) {
|
||||
return promisifyRequestCall(indexedDB, 'deleteDatabase', [name]);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = exp;
|
||||
}
|
||||
else {
|
||||
self.idb = exp;
|
||||
}
|
||||
}());
|
16
dashboard-ui/bower_components/emby-webcomponents/imageeditor/imageeditor.css
vendored
Normal file
16
dashboard-ui/bower_components/emby-webcomponents/imageeditor/imageeditor.css
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
.imageEditor-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 1em 0 1em;
|
||||
}
|
||||
|
||||
.first-imageEditor-buttons {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 1200px) {
|
||||
|
||||
.imageEditorCard {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require) {
|
||||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require) {
|
||||
'use strict';
|
||||
|
||||
var currentItem;
|
||||
|
@ -1,14 +1,4 @@
|
||||
<style>
|
||||
@media all and (min-width: 1200px) {
|
||||
|
||||
.imageEditorCard {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="formDialogHeader">
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${HeaderEditImages}
|
||||
@ -19,7 +9,7 @@
|
||||
<div class="dialogContentInner">
|
||||
|
||||
<div id="imagesContainer">
|
||||
<div style="display: flex; align-items: center;margin:2em 0 1em;">
|
||||
<div class="imageEditor-buttons first-imageEditor-buttons">
|
||||
<h1 style="margin:0;">${Images}</h1>
|
||||
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;">
|
||||
<i class="md-icon">search</i>
|
||||
@ -34,7 +24,7 @@
|
||||
</div>
|
||||
|
||||
<div id="backdropsContainer" class="hide">
|
||||
<div style="display: flex; align-items: center;margin:1em 0 1em;">
|
||||
<div class="imageEditor-buttons">
|
||||
<h1 style="margin:0;">${Backdrops}</h1>
|
||||
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Backdrop">
|
||||
<i class="md-icon">search</i>
|
||||
@ -49,7 +39,7 @@
|
||||
</div>
|
||||
|
||||
<div id="screenshotsContainer" class="hide">
|
||||
<div style="display: flex; align-items: center; margin: 1em 0 1em;">
|
||||
<div class="imageEditor-buttons">
|
||||
<h1 style="margin: 0;">${Screenshots}</h1>
|
||||
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Screenshot">
|
||||
<i class="md-icon">search</i>
|
||||
|
@ -1,50 +1,12 @@
|
||||
define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser', 'dom', 'appSettings', 'require'], function (visibleinviewport, imageFetcher, layoutManager, events, browser, dom, appSettings, require) {
|
||||
define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'require'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
|
||||
'use strict';
|
||||
|
||||
var thresholdX;
|
||||
var thresholdY;
|
||||
|
||||
var requestIdleCallback = window.requestIdleCallback || function (fn) {
|
||||
fn();
|
||||
};
|
||||
|
||||
//var imagesWorker = new Worker(require.toUrl('.').split('?')[0] + '/imagesworker.js');
|
||||
|
||||
var supportsIntersectionObserver = function () {
|
||||
|
||||
if (window.IntersectionObserver) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
function resetThresholds() {
|
||||
|
||||
var x = screen.availWidth;
|
||||
var y = screen.availHeight;
|
||||
|
||||
if (browser.touch) {
|
||||
x *= 1.5;
|
||||
y *= 1.5;
|
||||
}
|
||||
|
||||
thresholdX = x;
|
||||
thresholdY = y;
|
||||
}
|
||||
|
||||
if (!supportsIntersectionObserver) {
|
||||
dom.addEventListener(window, "orientationchange", resetThresholds, { passive: true });
|
||||
dom.addEventListener(window, 'resize', resetThresholds, { passive: true });
|
||||
resetThresholds();
|
||||
}
|
||||
|
||||
function isVisible(elem) {
|
||||
return visibleinviewport(elem, true, thresholdX, thresholdY);
|
||||
}
|
||||
|
||||
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
|
||||
var self = {};
|
||||
|
||||
var enableFade = browser.animate && !browser.slow;
|
||||
@ -65,7 +27,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
function fillImageElement(elem, source, enableEffects) {
|
||||
imageFetcher.loadImage(elem, source).then(function () {
|
||||
|
||||
var fillingVibrant = elem.tagName !== 'IMG' ? false : fillVibrant(elem, source);
|
||||
var fillingVibrant = fillVibrant(elem, source);
|
||||
|
||||
if (enableFade && !layoutManager.tv && enableEffects !== false && !fillingVibrant) {
|
||||
fadeIn(elem);
|
||||
@ -148,14 +110,17 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
requestIdleCallback(function () {
|
||||
|
||||
//var now = new Date().getTime();
|
||||
var swatch = getVibrantInfo(img, url).split('|');
|
||||
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
|
||||
if (swatch.length) {
|
||||
getVibrantInfoFromElement(img, url).then(function (vibrantInfo) {
|
||||
|
||||
var index = 0;
|
||||
vibrantElement.style.backgroundColor = swatch[index];
|
||||
vibrantElement.style.color = swatch[index + 1];
|
||||
}
|
||||
var swatch = vibrantInfo.split('|');
|
||||
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
|
||||
if (swatch.length) {
|
||||
|
||||
var index = 0;
|
||||
vibrantElement.style.backgroundColor = swatch[index];
|
||||
vibrantElement.style.color = swatch[index + 1];
|
||||
}
|
||||
});
|
||||
});
|
||||
/*
|
||||
* Results into:
|
||||
@ -167,6 +132,26 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
*/
|
||||
}
|
||||
|
||||
function getVibrantInfoFromElement(elem, url) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['vibrant'], function () {
|
||||
|
||||
if (elem.tagName === 'IMG') {
|
||||
resolve(getVibrantInfo(elem, url));
|
||||
return;
|
||||
}
|
||||
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
resolve(getVibrantInfo(img, url));
|
||||
};
|
||||
img.src = url;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getSettingsKey(url) {
|
||||
|
||||
var parts = url.split('://');
|
||||
@ -176,7 +161,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
|
||||
url = url.split('?')[0];
|
||||
|
||||
var cacheKey = 'vibrant25';
|
||||
var cacheKey = 'vibrant31';
|
||||
//cacheKey = 'vibrant' + new Date().getTime();
|
||||
return cacheKey + url;
|
||||
}
|
||||
@ -198,33 +183,21 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
|
||||
value = '';
|
||||
var swatch = swatches.DarkVibrant;
|
||||
if (swatch) {
|
||||
value += swatch.getHex() + '|' + swatch.getBodyTextColor();
|
||||
}
|
||||
//swatch = swatches.DarkMuted;
|
||||
//if (swatch) {
|
||||
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
|
||||
//} else {
|
||||
// value += '||';
|
||||
//}
|
||||
//swatch = swatches.Vibrant;
|
||||
//if (swatch) {
|
||||
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
|
||||
//} else {
|
||||
// value += '||';
|
||||
//}
|
||||
//swatch = swatches.Muted;
|
||||
//if (swatch) {
|
||||
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
|
||||
//} else {
|
||||
// value += '||';
|
||||
//}
|
||||
value += getSwatchString(swatch);
|
||||
|
||||
appSettings.set(getSettingsKey(url), value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getSwatchString(swatch) {
|
||||
|
||||
if (swatch) {
|
||||
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
|
||||
}
|
||||
return '||';
|
||||
}
|
||||
|
||||
function fadeIn(elem) {
|
||||
|
||||
var duration = layoutManager.tv ? 160 : 300;
|
||||
@ -236,135 +209,9 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function cancelAll(tokens) {
|
||||
for (var i = 0, length = tokens.length; i < length; i++) {
|
||||
|
||||
tokens[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function unveilWithIntersection(images, root) {
|
||||
|
||||
var filledCount = 0;
|
||||
|
||||
var options = {};
|
||||
|
||||
//options.rootMargin = "300%";
|
||||
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
for (var j = 0, length2 = entries.length; j < length2; j++) {
|
||||
var entry = entries[j];
|
||||
var target = entry.target;
|
||||
observer.unobserve(target);
|
||||
fillImage(target);
|
||||
filledCount++;
|
||||
}
|
||||
},
|
||||
options
|
||||
);
|
||||
// Start observing an element
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
observer.observe(images[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function unveilElements(images, root) {
|
||||
|
||||
if (!images.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (supportsIntersectionObserver) {
|
||||
unveilWithIntersection(images, root);
|
||||
return;
|
||||
}
|
||||
|
||||
var filledImages = [];
|
||||
var cancellationTokens = [];
|
||||
|
||||
function unveilInternal(tokenIndex) {
|
||||
|
||||
var anyFound = false;
|
||||
var out = false;
|
||||
|
||||
// TODO: This out construct assumes left to right, top to bottom
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
if (cancellationTokens[tokenIndex]) {
|
||||
return;
|
||||
}
|
||||
if (filledImages[i]) {
|
||||
continue;
|
||||
}
|
||||
var img = images[i];
|
||||
if (!out && isVisible(img)) {
|
||||
anyFound = true;
|
||||
filledImages[i] = true;
|
||||
fillImage(img);
|
||||
} else {
|
||||
|
||||
if (anyFound) {
|
||||
out = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!images.length) {
|
||||
dom.removeEventListener(document, 'focus', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(document, 'scroll', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(document, wheelEvent, unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(window, 'resize', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function unveil() {
|
||||
|
||||
cancelAll(cancellationTokens);
|
||||
|
||||
var index = cancellationTokens.length;
|
||||
cancellationTokens.length++;
|
||||
|
||||
setTimeout(function () {
|
||||
unveilInternal(index);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
dom.addEventListener(document, 'focus', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(document, 'scroll', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(document, wheelEvent, unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(window, 'resize', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
|
||||
unveil();
|
||||
}
|
||||
|
||||
function lazyChildren(elem) {
|
||||
|
||||
unveilElements(elem.getElementsByClassName('lazy'), elem);
|
||||
lazyLoader.lazyChildren(elem, fillImage);
|
||||
}
|
||||
|
||||
function getPrimaryImageAspectRatio(items) {
|
||||
@ -439,6 +286,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
|
||||
self.lazyChildren = lazyChildren;
|
||||
self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio;
|
||||
self.getCachedVibrantInfo = getCachedVibrantInfo;
|
||||
self.getVibrantInfoFromElement = getVibrantInfoFromElement;
|
||||
|
||||
return self;
|
||||
});
|
@ -14,7 +14,6 @@
|
||||
|
||||
.indicator {
|
||||
border-radius: 500px;
|
||||
display: -ms-flex;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -45,7 +44,6 @@
|
||||
.countIndicator {
|
||||
background: rgba(82,181,75,1);
|
||||
border-radius: 500px;
|
||||
display: -ms-flex;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -57,7 +55,6 @@
|
||||
.playedIndicator {
|
||||
background: rgba(82,181,75,1);
|
||||
border-radius: 500px;
|
||||
display: -ms-flex;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -49,13 +49,30 @@ define(['css!./indicators.css', 'material-icons'], function () {
|
||||
|
||||
function enablePlayedIndicator(item) {
|
||||
|
||||
if (item.Type === "Series" || item.Type === "Season" || item.Type === "BoxSet" || item.MediaType === "Video" || item.MediaType === "Game" || item.MediaType === "Book") {
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Audio') {
|
||||
if (item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
if (item.Type === 'AudioBook') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === "Series" ||
|
||||
item.Type === "Season" ||
|
||||
item.Type === "BoxSet" ||
|
||||
item.MediaType === "Game" ||
|
||||
item.MediaType === "Book" ||
|
||||
item.MediaType === "Recording") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
|
||||
});
|
||||
}
|
||||
|
||||
if (item.CanDelete) {
|
||||
if (item.CanDelete && options.deleteItem !== false) {
|
||||
|
||||
if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
|
||||
commands.push({
|
||||
@ -174,7 +174,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
if (item.Type === 'Program' && options.record !== false) {
|
||||
|
||||
commands.push({
|
||||
name: Globalize.translate('sharedcomponents#Record'),
|
||||
@ -184,7 +184,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
commands.push({
|
||||
name: globalize.translate('sharedcomponents#Refresh'),
|
||||
id: 'refresh'
|
||||
@ -233,7 +233,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
|
||||
}
|
||||
}
|
||||
|
||||
if (options.openAlbum !== false && item.AlbumId) {
|
||||
if (options.openAlbum !== false && item.AlbumId && item.MediaType !== 'Photo') {
|
||||
commands.push({
|
||||
name: Globalize.translate('sharedcomponents#ViewAlbum'),
|
||||
id: 'album'
|
||||
@ -577,25 +577,16 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var itemId = item.Id;
|
||||
require(['deleteHelper'], function (deleteHelper) {
|
||||
|
||||
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
|
||||
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm({
|
||||
|
||||
title: title,
|
||||
text: msg,
|
||||
confirmText: globalize.translate('sharedcomponents#Delete'),
|
||||
primary: 'cancel'
|
||||
deleteHelper.deleteItem({
|
||||
|
||||
item: item,
|
||||
navigate: false
|
||||
|
||||
}).then(function () {
|
||||
|
||||
apiClient.deleteItem(itemId).then(function () {
|
||||
resolve(true);
|
||||
});
|
||||
resolve(true);
|
||||
|
||||
}, reject);
|
||||
|
||||
|
@ -13,7 +13,7 @@ define(['apphost'], function (appHost) {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
var name = (item.Type === 'Program' && item.IsSeries ? item.EpisodeTitle : item.Name) || '';
|
||||
var name = ((item.Type === 'Program' || item.Type === 'Recording') && item.IsSeries ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === "TvChannel") {
|
||||
|
||||
@ -30,10 +30,10 @@ define(['apphost'], function (appHost) {
|
||||
|
||||
var displayIndexNumber = item.IndexNumber;
|
||||
|
||||
var number = "E" + displayIndexNumber;
|
||||
var number = displayIndexNumber;
|
||||
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = "S" + item.ParentIndexNumber + ", " + number;
|
||||
number = "S" + item.ParentIndexNumber + ", E" + number;
|
||||
}
|
||||
|
||||
if (item.IndexNumberEnd) {
|
||||
@ -71,6 +71,9 @@ define(['apphost'], function (appHost) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
@ -169,6 +172,12 @@ define(['apphost'], function (appHost) {
|
||||
|
||||
canShare: function (user, item) {
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
@ -181,6 +190,10 @@ define(['apphost'], function (appHost) {
|
||||
}
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
},
|
||||
|
||||
enableDateAddedDisplay: function(item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
}
|
||||
};
|
||||
});
|
@ -33,7 +33,6 @@
|
||||
}
|
||||
|
||||
.cardOverlayFab {
|
||||
background-color: #282828 !important;
|
||||
margin-right: .25em !important;
|
||||
}
|
||||
|
||||
|
94
dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js
vendored
Normal file
94
dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function LazyLoader(options) {
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
LazyLoader.prototype.createObserver = function () {
|
||||
|
||||
var observerOptions = {};
|
||||
var options = this.options;
|
||||
var loadedCount = 0;
|
||||
var callback = options.callback;
|
||||
|
||||
//options.rootMargin = "300%";
|
||||
|
||||
var observerId = 'obs' + new Date().getTime();
|
||||
|
||||
var self = this;
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
for (var j = 0, length2 = entries.length; j < length2; j++) {
|
||||
var entry = entries[j];
|
||||
var target = entry.target;
|
||||
|
||||
observer.unobserve(target);
|
||||
|
||||
if (!target[observerId]) {
|
||||
target[observerId] = 1;
|
||||
callback(target);
|
||||
loadedCount++;
|
||||
|
||||
if (loadedCount >= self.elementCount) {
|
||||
self.destroyObserver();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
observerOptions
|
||||
);
|
||||
|
||||
this.observer = observer;
|
||||
};
|
||||
|
||||
LazyLoader.prototype.addElements = function (elements) {
|
||||
|
||||
var observer = this.observer;
|
||||
|
||||
if (!observer) {
|
||||
this.createObserver();
|
||||
observer = this.observer;
|
||||
}
|
||||
|
||||
this.elementCount = (this.elementCount || 0) + elements.length;
|
||||
|
||||
for (var i = 0, length = elements.length; i < length; i++) {
|
||||
observer.observe(elements[i]);
|
||||
}
|
||||
};
|
||||
|
||||
LazyLoader.prototype.destroyObserver = function (elements) {
|
||||
|
||||
var observer = this.observer;
|
||||
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
this.observer = null;
|
||||
}
|
||||
};
|
||||
|
||||
LazyLoader.prototype.destroy = function (elements) {
|
||||
|
||||
this.destroyObserver();
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
function unveilElements(elements, root, callback) {
|
||||
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
var lazyLoader = new LazyLoader({
|
||||
callback: callback
|
||||
});
|
||||
lazyLoader.addElements(elements);
|
||||
}
|
||||
|
||||
LazyLoader.lazyChildren = function (elem, callback) {
|
||||
|
||||
unveilElements(elem.getElementsByClassName('lazy'), elem, callback);
|
||||
};
|
||||
|
||||
return LazyLoader;
|
||||
});
|
185
dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js
vendored
Normal file
185
dashboard-ui/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
define(['visibleinviewport', 'browser', 'dom'], function (visibleinviewport, browser, dom) {
|
||||
'use strict';
|
||||
|
||||
var thresholdX;
|
||||
var thresholdY;
|
||||
|
||||
var requestIdleCallback = window.requestIdleCallback || function (fn) {
|
||||
fn();
|
||||
};
|
||||
|
||||
function resetThresholds() {
|
||||
|
||||
var x = screen.availWidth;
|
||||
var y = screen.availHeight;
|
||||
|
||||
if (browser.touch) {
|
||||
x *= 1.5;
|
||||
y *= 1.5;
|
||||
}
|
||||
|
||||
thresholdX = x;
|
||||
thresholdY = y;
|
||||
}
|
||||
|
||||
dom.addEventListener(window, "orientationchange", resetThresholds, { passive: true });
|
||||
dom.addEventListener(window, 'resize', resetThresholds, { passive: true });
|
||||
resetThresholds();
|
||||
|
||||
function isVisible(elem) {
|
||||
return visibleinviewport(elem, true, thresholdX, thresholdY);
|
||||
}
|
||||
|
||||
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
|
||||
var self = {};
|
||||
|
||||
function cancelAll(tokens) {
|
||||
for (var i = 0, length = tokens.length; i < length; i++) {
|
||||
|
||||
tokens[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function unveilElementsInternal(instance, callback) {
|
||||
|
||||
var unveiledElements = [];
|
||||
var cancellationTokens = [];
|
||||
var loadedCount = 0;
|
||||
|
||||
function unveilInternal(tokenIndex) {
|
||||
|
||||
var anyFound = false;
|
||||
var out = false;
|
||||
|
||||
var elements = instance.elements;
|
||||
// TODO: This out construct assumes left to right, top to bottom
|
||||
|
||||
for (var i = 0, length = elements.length; i < length; i++) {
|
||||
|
||||
if (cancellationTokens[tokenIndex]) {
|
||||
return;
|
||||
}
|
||||
if (unveiledElements[i]) {
|
||||
continue;
|
||||
}
|
||||
var elem = elements[i];
|
||||
if (!out && isVisible(elem)) {
|
||||
anyFound = true;
|
||||
unveiledElements[i] = true;
|
||||
callback(elem);
|
||||
loadedCount++;
|
||||
} else {
|
||||
|
||||
if (anyFound) {
|
||||
out = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedCount >= elements.length) {
|
||||
dom.removeEventListener(document, 'focus', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(document, 'scroll', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(document, wheelEvent, unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(window, 'resize', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function unveil() {
|
||||
|
||||
cancelAll(cancellationTokens);
|
||||
|
||||
var index = cancellationTokens.length;
|
||||
cancellationTokens.length++;
|
||||
|
||||
setTimeout(function () {
|
||||
unveilInternal(index);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
dom.addEventListener(document, 'focus', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(document, 'scroll', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(document, wheelEvent, unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(window, 'resize', unveil, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
|
||||
unveil();
|
||||
}
|
||||
|
||||
function LazyLoader(options) {
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
LazyLoader.prototype.createObserver = function () {
|
||||
|
||||
unveilElementsInternal(this, this.options.callback);
|
||||
this.observer = 1;
|
||||
};
|
||||
|
||||
LazyLoader.prototype.addElements = function (elements) {
|
||||
|
||||
this.elements = this.elements || [];
|
||||
|
||||
for (var i = 0, length = elements.length; i < length; i++) {
|
||||
this.elements.push(elements[i]);
|
||||
}
|
||||
|
||||
var observer = this.observer;
|
||||
|
||||
if (!observer) {
|
||||
this.createObserver();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
LazyLoader.prototype.destroyObserver = function (elements) {
|
||||
|
||||
};
|
||||
|
||||
LazyLoader.prototype.destroy = function (elements) {
|
||||
|
||||
this.destroyObserver();
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
function unveilElements(elements, root, callback) {
|
||||
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
var lazyLoader = new LazyLoader({
|
||||
callback: callback
|
||||
});
|
||||
lazyLoader.addElements(elements);
|
||||
}
|
||||
|
||||
LazyLoader.lazyChildren = function (elem, callback) {
|
||||
|
||||
unveilElements(elem.getElementsByClassName('lazy'), elem, callback);
|
||||
};
|
||||
|
||||
return LazyLoader;
|
||||
});
|
@ -100,8 +100,8 @@
|
||||
}
|
||||
|
||||
.listItemIcon {
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
width: 1em !important;
|
||||
height: 1em !important;
|
||||
font-size: 143%;
|
||||
border-radius: 500px;
|
||||
background-color: #52B54B;
|
||||
@ -166,12 +166,9 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@supports (display: flex) {
|
||||
|
||||
.listItem, .listItemBody, .listItemMediaInfo {
|
||||
display: flex;
|
||||
contain: layout style;
|
||||
}
|
||||
.listItem, .listItemBody, .listItemMediaInfo {
|
||||
display: flex;
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
@media all and (max-width: 800px) {
|
||||
|
@ -310,7 +310,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
textlines.push(displayName);
|
||||
}
|
||||
|
||||
if (options.artist !== false) {
|
||||
if (options.artist !== false && (options.artist === true || item.AlbumArtist !== options.containerAlbumArtist)) {
|
||||
|
||||
if (item.ArtistItems && item.Type !== 'MusicAlbum') {
|
||||
textlines.push(item.ArtistItems.map(function (a) {
|
||||
return a.Name;
|
||||
@ -318,7 +319,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}).join(', '));
|
||||
}
|
||||
|
||||
if (item.AlbumArtist && item.Type === 'MusicAlbum') {
|
||||
else if (item.AlbumArtist && item.Type === 'MusicAlbum') {
|
||||
textlines.push(item.AlbumArtist);
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,23 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
|
||||
}
|
||||
}
|
||||
|
||||
if (item.StartDate && item.Type !== 'Program') {
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
miscInfo.push(globalize.translate('sharedcomponents#Anytime'));
|
||||
} else {
|
||||
miscInfo.push(datetime.getDisplayTime(item.StartDate));
|
||||
}
|
||||
|
||||
if (item.RecordAnyChannel) {
|
||||
miscInfo.push(globalize.translate('sharedcomponents#AllChannels'));
|
||||
}
|
||||
else {
|
||||
miscInfo.push(item.ChannelName || globalize.translate('sharedcomponents#OneChannel'));
|
||||
}
|
||||
}
|
||||
|
||||
if (item.StartDate && item.Type !== 'Program' && item.Type !== 'SeriesTimer') {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
@ -453,6 +469,160 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
|
||||
return '';
|
||||
}
|
||||
|
||||
function getResolutionText(item) {
|
||||
|
||||
if (!item.MediaSources || !item.MediaSources.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return item.MediaSources[0].MediaStreams.filter(function (i) {
|
||||
|
||||
return i.Type === 'Video';
|
||||
|
||||
}).map(function (i) {
|
||||
|
||||
if (i.Height) {
|
||||
|
||||
if (i.Width >= 3800) {
|
||||
return '4K';
|
||||
}
|
||||
if (i.Width >= 2500) {
|
||||
return '1440P';
|
||||
}
|
||||
if (i.Width >= 1900) {
|
||||
return '1080P';
|
||||
}
|
||||
if (i.Width >= 1260) {
|
||||
return '720P';
|
||||
}
|
||||
if (i.Width >= 700) {
|
||||
return '480P';
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
})[0];
|
||||
|
||||
}
|
||||
|
||||
function getAudioStreamForDisplay(item) {
|
||||
|
||||
if (!item.MediaSources) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var mediaSource = item.MediaSources[0];
|
||||
if (!mediaSource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (mediaSource.MediaStreams || []).filter(function (i) {
|
||||
return i.Type === 'Audio' && (i.Index === mediaSource.DefaultAudioStreamIndex || mediaSource.DefaultAudioStreamIndex == null);
|
||||
})[0];
|
||||
}
|
||||
|
||||
function getMediaInfoStats(item, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
var list = [];
|
||||
|
||||
if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) {
|
||||
list.push({
|
||||
type: 'added',
|
||||
text: globalize.translate('sharedcomponents#AddedOnValue', datetime.toLocaleDateString(datetime.parseISO8601Date(item.DateCreated)))
|
||||
});
|
||||
}
|
||||
|
||||
if (!item.MediaSources) {
|
||||
return list;
|
||||
}
|
||||
|
||||
var mediaSource = item.MediaSources[0];
|
||||
if (!mediaSource) {
|
||||
return list;
|
||||
}
|
||||
|
||||
var videoStream = (mediaSource.MediaStreams || []).filter(function (i) {
|
||||
return i.Type === 'Video';
|
||||
})[0] || {};
|
||||
var audioStream = getAudioStreamForDisplay(item) || {};
|
||||
|
||||
if (item.VideoType === 'Dvd') {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: 'Dvd'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.VideoType === 'BluRay') {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: 'BluRay'
|
||||
});
|
||||
}
|
||||
|
||||
//if (mediaSource.Container) {
|
||||
// html += '<div class="mediaInfoIcon mediaInfoText">' + mediaSource.Container + '</div>';
|
||||
//}
|
||||
|
||||
var resolutionText = getResolutionText(item);
|
||||
if (resolutionText) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: resolutionText
|
||||
});
|
||||
}
|
||||
|
||||
if (videoStream.Codec) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: videoStream.Codec
|
||||
});
|
||||
}
|
||||
|
||||
var channels = audioStream.Channels;
|
||||
var channelText;
|
||||
|
||||
if (channels === 8) {
|
||||
|
||||
channelText = '7.1';
|
||||
|
||||
} else if (channels === 7) {
|
||||
|
||||
channelText = '6.1';
|
||||
|
||||
} else if (channels === 6) {
|
||||
|
||||
channelText = '5.1';
|
||||
|
||||
} else if (channels === 2) {
|
||||
|
||||
channelText = '2.0';
|
||||
}
|
||||
|
||||
if (channelText) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: channelText
|
||||
});
|
||||
}
|
||||
|
||||
if (audioStream.Codec === 'dca' && audioStream.Profile) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: audioStream.Profile
|
||||
});
|
||||
} else if (audioStream.Codec) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
text: audioStream.Codec
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return {
|
||||
getMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
fill: fillPrimaryMediaInfo,
|
||||
@ -461,6 +631,7 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
|
||||
getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml,
|
||||
fillPrimaryMediaInfo: fillPrimaryMediaInfo,
|
||||
fillSecondaryMediaInfo: fillSecondaryMediaInfo
|
||||
fillSecondaryMediaInfo: fillSecondaryMediaInfo,
|
||||
getMediaInfoStats: getMediaInfoStats
|
||||
};
|
||||
});
|
@ -700,14 +700,14 @@
|
||||
showElement('#fldCustomRating', context);
|
||||
}
|
||||
|
||||
showElement('#tagsCollapsible', context);
|
||||
|
||||
if (item.Type === "TvChannel") {
|
||||
hideElement('#tagsCollapsible', context);
|
||||
hideElement('#metadataSettingsCollapsible', context);
|
||||
hideElement('#fldPremiereDate', context);
|
||||
hideElement('#fldDateAdded', context);
|
||||
hideElement('#fldYear', context);
|
||||
} else {
|
||||
showElement('#tagsCollapsible', context);
|
||||
showElement('#metadataSettingsCollapsible', context);
|
||||
showElement('#fldPremiereDate', context);
|
||||
showElement('#fldDateAdded', context);
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
(function UMD(name,context,definition){
|
||||
// special form of UMD for polyfilling across evironments
|
||||
context[name] = context[name] || definition();
|
||||
context[name] = definition();
|
||||
if (typeof module != "undefined" && module.exports) { module.exports = context[name]; }
|
||||
else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); }
|
||||
})("Promise",typeof global != "undefined" ? global : this,function DEF(){
|
@ -139,7 +139,8 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
||||
Filters: "IsNotFolder",
|
||||
SortBy: "DateCreated",
|
||||
SortOrder: "Descending",
|
||||
Ids: newItems.join(',')
|
||||
Ids: newItems.join(','),
|
||||
MediaTypes: "Audio,Video"
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
|
@ -127,6 +127,12 @@
|
||||
|
||||
select.innerHTML = html;
|
||||
select.value = userSettings.get('playlisteditor-lastplaylistid') || '';
|
||||
|
||||
// If the value is empty set it again, in case we tried to set a lastplaylistid that is no longer valid
|
||||
if (!select.value) {
|
||||
select.value = '';
|
||||
}
|
||||
|
||||
triggerChange(select);
|
||||
|
||||
loading.hide();
|
||||
|
@ -19,4 +19,18 @@
|
||||
|
||||
.recordingDialog-btnRecord {
|
||||
background-color: #cc3333;
|
||||
}
|
||||
}
|
||||
|
||||
.recordingDetailsContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.recordingDetails {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.recordingDetailText {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
@ -5,14 +5,14 @@
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<form class="dialogContentInner dialog-content-centered">
|
||||
|
||||
<div style="display: flex;">
|
||||
<div class="recordingDetailsContainer">
|
||||
<div class="recordingDialog-imageContainer">
|
||||
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
<div class="recordingDetails">
|
||||
<h1 class="programDialog-itemName recordingDialog-itemName dialogContentTitle"></h1>
|
||||
<p class="itemMiscInfoPrimary" style="display: flex; align-items: center; flex-wrap: wrap;"></p>
|
||||
<p class="itemMiscInfoSecondary secondaryText" style="display: flex; align-items: center; flex-wrap: wrap;"></p>
|
||||
<p class="itemMiscInfoPrimary recordingDetailText"></p>
|
||||
<p class="itemMiscInfoSecondary recordingDetailText secondaryText"></p>
|
||||
<p class="itemGenres secondaryText"></p>
|
||||
|
||||
<div style="margin:.5em 0 1em;" class="recordingFields">
|
||||
|
44
dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.css
vendored
Normal file
44
dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.css
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
.recordingButton {
|
||||
margin-left: 0;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.recordingIcon {
|
||||
font-size: 1.3em !important;
|
||||
}
|
||||
|
||||
.recordingIcon-active {
|
||||
color: #cc3333;
|
||||
}
|
||||
|
||||
.manageButtonText {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.recordSeriesContainer {
|
||||
margin-bottom: .8em;
|
||||
}
|
||||
|
||||
.recordingFields-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media all and (max-width: 440px) {
|
||||
|
||||
.manageButtonText {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.recordingButton {
|
||||
width: auto;
|
||||
margin-right: 1.5em !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 440px) {
|
||||
|
||||
.manageButtonIcon {
|
||||
font-size: 90% !important;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'registrationServices', 'paper-icon-button-light', 'emby-button'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events, registrationServices) {
|
||||
define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'registrationServices', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events, registrationServices) {
|
||||
'use strict';
|
||||
|
||||
function getRegistration(apiClient, programId, feature) {
|
||||
@ -106,21 +106,21 @@
|
||||
}
|
||||
|
||||
if (program.SeriesTimerId) {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.remove('visibilityHide');
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.remove('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#CancelSeries');
|
||||
} else {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.add('visibilityHide');
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#RecordSeries');
|
||||
}
|
||||
|
||||
if (program.TimerId && program.Status !== 'Cancelled') {
|
||||
parent.querySelector('.btnManageRecording').classList.remove('visibilityHide');
|
||||
parent.querySelector('.btnManageRecording').classList.remove('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#DoNotRecord');
|
||||
} else {
|
||||
parent.querySelector('.btnManageRecording').classList.add('visibilityHide');
|
||||
parent.querySelector('.btnManageRecording').classList.add('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#Record');
|
||||
}
|
||||
|
@ -1,47 +1,4 @@
|
||||
<style>
|
||||
.visibilityHide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.recordingButton {
|
||||
margin-left: 0;
|
||||
min-width: 10em;
|
||||
font-size: 92%;
|
||||
}
|
||||
|
||||
.recordingIcon {
|
||||
font-size: 1.3em !important;
|
||||
}
|
||||
|
||||
.recordingIcon-active {
|
||||
color: #cc3333;
|
||||
}
|
||||
|
||||
.manageButtonText {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
@media all and (max-width: 440px) {
|
||||
|
||||
.manageButtonText {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.recordingButton {
|
||||
width: auto;
|
||||
margin-right: 1.5em !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 440px) {
|
||||
|
||||
.manageButtonIcon {
|
||||
font-size: 90% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="convertRecordingsContainer hide" style="padding: 1.25em 1.5em; background: #242424; border-radius: 3px; margin: 1em 0 2em;">
|
||||
<div class="convertRecordingsContainer hide" style="padding: 1.25em 1.5em; background: #242424; border-radius: 3px; margin: 1em 0 2em;">
|
||||
<h1 style="margin: .25em 0 .5em;">${HeaderConvertYourRecordings}</h1>
|
||||
<div class="fieldDescription">${PromoConvertRecordingsToStreamingFormat}</div>
|
||||
<br />
|
||||
@ -58,27 +15,27 @@
|
||||
</div>
|
||||
<div class="recordingFields hide">
|
||||
|
||||
<div class="recordSeriesContainer hide" style="display: flex; align-items: center;margin-bottom:.8em;">
|
||||
<div class="recordSeriesContainer recordingFields-buttons hide">
|
||||
<div>
|
||||
<button is="emby-button" type="button" class="raised button-cancel recordingButton seriesRecordingButton">
|
||||
<i class="md-icon recordingIcon"></i>
|
||||
<span class="buttonText">${RecordSeries}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageSeriesRecording visibilityHide">
|
||||
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageSeriesRecording hide">
|
||||
<i class="md-icon manageButtonIcon">settings</i>
|
||||
<span class="manageButtonText">${SeriesSettings}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div class="recordingFields-buttons">
|
||||
<div>
|
||||
<button is="emby-button" type="button" class="raised button-cancel recordingButton singleRecordingButton">
|
||||
<i class="md-icon recordingIcon"></i>
|
||||
<span class="buttonText">${Record}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageRecording visibilityHide">
|
||||
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageRecording hide">
|
||||
<i class="md-icon manageButtonIcon">settings</i>
|
||||
<span class="manageButtonText">${Settings}</span>
|
||||
</button>
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['globalize', 'loading'], function (globalize, loading) {
|
||||
define(['globalize', 'loading', 'connectionManager'], function (globalize, loading, connectionManager) {
|
||||
'use strict';
|
||||
|
||||
function changeRecordingToSeries(apiClient, timerId, programId) {
|
||||
|
@ -98,15 +98,24 @@
|
||||
|
||||
function reload(context, id) {
|
||||
|
||||
loading.show();
|
||||
currentItemId = id;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
||||
|
||||
renderTimer(context, result, apiClient);
|
||||
loading.show();
|
||||
if (typeof id === 'string') {
|
||||
currentItemId = id;
|
||||
|
||||
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
||||
|
||||
renderTimer(context, result, apiClient);
|
||||
loading.hide();
|
||||
});
|
||||
} else if (id) {
|
||||
|
||||
currentItemId = id.Id;
|
||||
|
||||
renderTimer(context, id, apiClient);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function fillKeepUpTo(context) {
|
||||
@ -130,6 +139,10 @@
|
||||
|
||||
context.querySelector('.selectKeepUpTo').innerHTML = html;
|
||||
}
|
||||
|
||||
function onFieldChange(e) {
|
||||
this.querySelector('.btnSubmit').click();
|
||||
}
|
||||
|
||||
function embed(itemId, serverId, options) {
|
||||
|
||||
@ -163,9 +176,8 @@
|
||||
dlg.querySelector('.dialogContentInner').className = '';
|
||||
dlg.classList.remove('hide');
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
dlg.querySelector('.btnSubmit').click();
|
||||
});
|
||||
dlg.removeEventListener('change', onFieldChange);
|
||||
dlg.addEventListener('change', onFieldChange);
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">
|
||||
|
||||
<form>
|
||||
<form style="max-width: none;">
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" class="selectShowType" label="${LabelRecord}">
|
||||
<option value="new">${NewEpisodesOnly}</option>
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkSkipEpisodesInLibrary"/>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkSkipEpisodesInLibrary" />
|
||||
<span>${SkipEpisodesAlreadyInMyLibrary}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${SkipEpisodesAlreadyInMyLibraryHelp}</div>
|
||||
@ -39,8 +39,7 @@
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" class="selectKeepUpTo" label="${LabelKeepUpTo}">
|
||||
</select>
|
||||
<select is="emby-select" class="selectKeepUpTo" label="${LabelKeepUpTo}"></select>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
html += '<br />';
|
||||
html += '<div class="formDialogFooter">';
|
||||
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#ButtonOk') + '</button>';
|
||||
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#Refresh') + '</button>';
|
||||
html += '</div>';
|
||||
|
||||
html += '</form>';
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['loading', 'dom', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'pageJs', 'appSettings', 'apphost'], function (loading, dom, viewManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost) {
|
||||
define(['loading', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'pageJs', 'appSettings', 'apphost'], function (loading, viewManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost) {
|
||||
'use strict';
|
||||
|
||||
var embyRouter = {
|
||||
@ -491,16 +491,12 @@ define(['loading', 'dom', 'viewManager', 'skinManager', 'pluginManager', 'backdr
|
||||
}
|
||||
|
||||
var resolveOnNextShow;
|
||||
dom.addEventListener(document, 'viewshow', function () {
|
||||
|
||||
document.addEventListener('viewshow', function () {
|
||||
var resolve = resolveOnNextShow;
|
||||
if (resolve) {
|
||||
resolveOnNextShow = null;
|
||||
resolve();
|
||||
}
|
||||
}, {
|
||||
passive: true,
|
||||
once: true
|
||||
});
|
||||
|
||||
var currentRouteInfo;
|
||||
|
@ -873,6 +873,11 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'scrollStyles'], func
|
||||
}
|
||||
} else {
|
||||
slideeElement.style['will-change'] = 'transform';
|
||||
if (o.horizontal) {
|
||||
slideeElement.classList.add('animatedScrollX');
|
||||
} else {
|
||||
slideeElement.classList.add('animatedScrollY');
|
||||
}
|
||||
}
|
||||
|
||||
dragSourceElement.addEventListener('mousedown', dragInitSlidee);
|
||||
|
@ -33,3 +33,22 @@
|
||||
width: 0 !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.darkScroller::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.darkScroller::-webkit-scrollbar-button:start:decrement,
|
||||
.darkScroller::-webkit-scrollbar-button:end:increment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.darkScroller::-webkit-scrollbar-track-piece {
|
||||
background-color: #3b3b3b;
|
||||
}
|
||||
|
||||
.darkScroller::-webkit-scrollbar-thumb:vertical, .darkScroller::-webkit-scrollbar-thumb:horizontal {
|
||||
-webkit-border-radius: 2px;
|
||||
background: #888 no-repeat center;
|
||||
}
|
||||
|
@ -225,6 +225,8 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
|
||||
var serverId = item.ServerId;
|
||||
var type = item.Type;
|
||||
|
||||
var playableItemId = type === 'Program' ? item.ChannelId : item.Id;
|
||||
|
||||
if (action === 'link') {
|
||||
|
||||
showItem(item, {
|
||||
@ -238,7 +240,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
|
||||
}
|
||||
|
||||
else if (action === 'instantmix') {
|
||||
playbackManager.instantMix(id, serverId);
|
||||
playbackManager.instantMix(playableItemId, serverId);
|
||||
}
|
||||
|
||||
else if (action === 'play') {
|
||||
@ -246,7 +248,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
|
||||
var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
|
||||
|
||||
playbackManager.play({
|
||||
ids: [id],
|
||||
ids: [playableItemId],
|
||||
startPositionTicks: startPositionTicks,
|
||||
serverId: serverId
|
||||
});
|
||||
@ -410,11 +412,17 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
|
||||
}
|
||||
}
|
||||
|
||||
function getShortcutAttributesHtml(item) {
|
||||
|
||||
return 'data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"';
|
||||
}
|
||||
|
||||
return {
|
||||
on: on,
|
||||
off: off,
|
||||
onClick: onClick,
|
||||
showContextMenu: showContextMenu
|
||||
showContextMenu: showContextMenu,
|
||||
getShortcutAttributesHtml: getShortcutAttributesHtml
|
||||
};
|
||||
|
||||
});
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Opcions de Visualitzaci\u00f3",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Ordre de visualitzaci\u00f3:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -1,37 +1,37 @@
|
||||
{
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.",
|
||||
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.",
|
||||
"MessageToValidateSupporter": "If you have an active Emby Premiere subscription, ensure you've setup Emby Premiere in your Emby Server Dashboard, which you can access by clicking Emby Premiere within the main menu.",
|
||||
"ValueSpecialEpisodeName": "Special - {0}",
|
||||
"Share": "Share",
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Odemknout tuto funkci pomoc\u00ed jednor\u00e1zov\u00e9 platby, nebo pomoc\u00ed aktivace p\u0159edplatn\u00e9ho Emby Premiere.",
|
||||
"MessageUnlockAppWithSupporter": "Odemknout tuto funkci pomoc\u00ed aktivn\u00edho p\u0159edplatn\u00e9ho Emby Premiere.",
|
||||
"MessageToValidateSupporter": "Pokud m\u00e1te aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere, ujist\u011bte se, \u017ee m\u00e1te nastaven Emby Premiere v panelu Nastaven\u00ed pod N\u00e1pov\u011bda -> Emby Premiere.",
|
||||
"ValueSpecialEpisodeName": "Speci\u00e1l - {0}",
|
||||
"Share": "Sd\u00edlet",
|
||||
"Add": "P\u0159idat",
|
||||
"ServerUpdateNeeded": "Tento Emby Server je t\u0159eba aktualizovat. Chcete-li st\u00e1hnout nejnov\u011bj\u0161\u00ed verzi, nav\u0161tivte pros\u00edm {0}",
|
||||
"LiveTvGuideRequiresUnlock": "Live TV programov\u00fd pr\u016fvodce je v sou\u010dasn\u00e9 dob\u011b omezen na {0} kan\u00e1l\u016f. Odemknut\u00edm se m\u016f\u017eete nau\u010dit jak si u\u017e\u00edt tuto funkci.",
|
||||
"AttributeNew": "New",
|
||||
"Premiere": "Premiere",
|
||||
"Live": "Live",
|
||||
"AttributeNew": "Nov\u00e9",
|
||||
"Premiere": "Premi\u00e9ra",
|
||||
"Live": "\u017div\u011b",
|
||||
"Repeat": "Opakovat",
|
||||
"TrackCount": "{0} tracks",
|
||||
"TrackCount": "{0} stop",
|
||||
"ItemCount": "{0} polo\u017eek",
|
||||
"ReleaseYearValue": "Release year: {0}",
|
||||
"OriginalAirDateValue": "Original air date: {0}",
|
||||
"EndsAtValue": "Ends at {0}",
|
||||
"OptionSundayShort": "Sun",
|
||||
"OptionMondayShort": "Mon",
|
||||
"OptionTuesdayShort": "Tue",
|
||||
"OptionWednesdayShort": "Wed",
|
||||
"OptionThursdayShort": "Thu",
|
||||
"OptionFridayShort": "Fri",
|
||||
"OptionSaturdayShort": "Sat",
|
||||
"ReleaseYearValue": "Rok vyd\u00e1n\u00ed: {0}",
|
||||
"OriginalAirDateValue": "Datum vys\u00edl\u00e1n\u00ed origin\u00e1lu: {0}",
|
||||
"EndsAtValue": "Kon\u010d\u00ed v {0}",
|
||||
"OptionSundayShort": "Ned",
|
||||
"OptionMondayShort": "Pon",
|
||||
"OptionTuesdayShort": "\u00date",
|
||||
"OptionWednesdayShort": "St\u0159",
|
||||
"OptionThursdayShort": "\u010ctv",
|
||||
"OptionFridayShort": "P\u00e1t",
|
||||
"OptionSaturdayShort": "Sob",
|
||||
"HeaderSelectDate": "Vyber datum",
|
||||
"ButtonOk": "Ok",
|
||||
"ButtonCancel": "Zru\u0161it",
|
||||
"ButtonGotIt": "M\u00e1m to",
|
||||
"ButtonRestart": "Restart",
|
||||
"RecordingCancelled": "Nahr\u00e1v\u00e1n\u00ed zru\u0161eno.",
|
||||
"SeriesCancelled": "Series cancelled.",
|
||||
"SeriesCancelled": "S\u00e9rie zru\u0161ena.",
|
||||
"RecordingScheduled": "Pl\u00e1n nahr\u00e1v\u00e1n\u00ed.",
|
||||
"SeriesRecordingScheduled": "Series recording scheduled.",
|
||||
"SeriesRecordingScheduled": "Pl\u00e1n nahr\u00e1v\u00e1n\u00ed seri\u00e1lu.",
|
||||
"HeaderNewRecording": "Nov\u00fd z\u00e1znam",
|
||||
"Sunday": "Ned\u011ble",
|
||||
"Monday": "Pond\u011bl\u00ed",
|
||||
@ -41,23 +41,23 @@
|
||||
"Friday": "P\u00e1tek",
|
||||
"Saturday": "Sobota",
|
||||
"Days": "Dny",
|
||||
"RecordSeries": "Record series",
|
||||
"HeaderCinemaMode": "Cinema Mode",
|
||||
"HeaderCloudSync": "Cloud Sync",
|
||||
"HeaderOfflineDownloads": "Offline Media",
|
||||
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.",
|
||||
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.",
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
|
||||
"CoverArt": "Cover Art",
|
||||
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
|
||||
"HeaderFreeApps": "Free Emby Apps",
|
||||
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.",
|
||||
"RecordSeries": "Nahr\u00e1t s\u00e9rie",
|
||||
"HeaderCinemaMode": "Cinema M\u00f3d",
|
||||
"HeaderCloudSync": "Synchronizace s Cloudem",
|
||||
"HeaderOfflineDownloads": "Offline m\u00e9dia",
|
||||
"HeaderOfflineDownloadsDescription": "St\u00e1hnout m\u00e9dia do va\u0161eho za\u0159\u00edzen\u00ed pro snadn\u00e9 pou\u017eit\u00ed offline.",
|
||||
"CloudSyncFeatureDescription": "Synchronizujte va\u0161e m\u00e9dia na cloud pro jednodu\u0161\u0161\u00ed z\u00e1lohov\u00e1n\u00ed, archivaci a konverzi.",
|
||||
"CoverArtFeatureDescription": "Cover Art vytv\u00e1\u0159\u00ed z\u00e1bavn\u00e9 obaly a dal\u0161\u00ed mo\u017enosti \u00faprav, kter\u00e9 v\u00e1m pomohou p\u0159izp\u016fsobit va\u0161e medi\u00e1ln\u00ed obr\u00e1zky.",
|
||||
"CoverArt": "Obal",
|
||||
"CinemaModeFeatureDescription": "S re\u017eimem Kino z\u00edskate funkci, kter\u00e1 p\u0159ed hlavn\u00edm programem p\u0159ehraje trailery a u\u017eivatelsk\u00e1 intra.",
|
||||
"HeaderFreeApps": "Emby Apps zdarma",
|
||||
"FreeAppsFeatureDescription": "U\u017eijte si v\u00fdb\u011br Emby aplikac\u00ed zdarma pro va\u0161e za\u0159\u00edzen\u00ed.",
|
||||
"HeaderBecomeProjectSupporter": "Z\u00edskat Emby Premiere",
|
||||
"MessageActiveSubscriptionRequiredSeriesRecordings": "Aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere je zapot\u0159eb\u00ed pro vytvo\u0159en\u00ed automatick\u00e9ho nahr\u00e1v\u00e1n\u00ed \u0159ad.",
|
||||
"LabelEmailAddress": "E-mail address:",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Emby Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Emby server settings.",
|
||||
"LabelEmailAddress": "E-mailov\u00e1 adresa:",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Automaticky konvertovat nahr\u00e1vky do dopore\u010den\u00e9ho streamovac\u00edho form\u00e1tu s Emby Premiere. Nahr\u00e1vky budou p\u0159ehr\u00e1v\u00e1n\u00ed konvertov\u00e1ny do MP4 nebo MKV - dle nastaven\u00ed Emby server.",
|
||||
"FeatureRequiresEmbyPremiere": "Tato funkce vy\u017eaduje aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere.",
|
||||
"HeaderConvertYourRecordings": "Convert Your Recordings",
|
||||
"HeaderConvertYourRecordings": "Konverze va\u0161ich nahr\u00e1vek",
|
||||
"Record": "Nahr\u00e1vat",
|
||||
"Save": "Ulo\u017eit",
|
||||
"Edit": "Upravit",
|
||||
@ -67,38 +67,38 @@
|
||||
"HeaderDeleteItem": "Smazat polo\u017eku",
|
||||
"ConfirmDeleteItem": "Smaz\u00e1n\u00edm polo\u017eky odstran\u00edte soubor jak z knihovny m\u00e9di\u00ed tak ze souborov\u00e9ho syst\u00e9mu. Jste si jisti, \u017ee chcete pokra\u010dovat?",
|
||||
"Refresh": "Obnovit",
|
||||
"RefreshQueued": "Refresh queued.",
|
||||
"AddToCollection": "Add to collection",
|
||||
"RefreshQueued": "Obnoven\u00ed za\u0159azeno.",
|
||||
"AddToCollection": "P\u0159idat do kolekce",
|
||||
"HeaderAddToCollection": "P\u0159idat do Kolekce",
|
||||
"NewCollection": "Nov\u00e1 kolekce",
|
||||
"LabelCollection": "Collection:",
|
||||
"LabelCollection": "Kolekce:",
|
||||
"Help": "N\u00e1pov\u011bda",
|
||||
"NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.",
|
||||
"NewCollectionHelp": "Kolekce dovol\u00ed vytvo\u0159it personalizovan\u00e9 seskupen\u00ed film\u016f a dal\u0161\u00edho obsahu knihoven.",
|
||||
"SearchForCollectionInternetMetadata": "Vyhledat metadata a obr\u00e1zky na Internetu.",
|
||||
"LabelName": "Jm\u00e9no:",
|
||||
"NewCollectionNameExample": "P\u0159\u00edklad: Kolekce Star Wars",
|
||||
"MessageItemsAdded": "Items added.",
|
||||
"MessageItemsAdded": "Polo\u017eka p\u0159id\u00e1na.",
|
||||
"OptionNew": "Nov\u00fd...",
|
||||
"LabelPlaylist": "Playlist:",
|
||||
"AddToPlaylist": "P\u0159idat do playlistu",
|
||||
"HeaderAddToPlaylist": "P\u0159idat do playlistu",
|
||||
"Subtitles": "Subtitles",
|
||||
"Subtitles": "Titulky",
|
||||
"SearchForSubtitles": "Vyhledat titulky",
|
||||
"LabelLanguage": "Jazyk:",
|
||||
"Search": "Vyhled\u00e1v\u00e1n\u00ed",
|
||||
"NoSubtitleSearchResultsFound": "No results found.",
|
||||
"NoSubtitleSearchResultsFound": "\u017d\u00e1dn\u00e9 v\u00fdsledky.",
|
||||
"File": "Soubor",
|
||||
"MessageAreYouSureDeleteSubtitles": "Jste si jisti, \u017ee chcete smazat tyto titulky?",
|
||||
"ConfirmDeletion": "Potvrdit smaz\u00e1n\u00ed",
|
||||
"MySubtitles": "My Subtitles",
|
||||
"MessageDownloadQueued": "Download queued.",
|
||||
"MySubtitles": "M\u00e9 titulky",
|
||||
"MessageDownloadQueued": "Sta\u017een\u00ed za\u0159azeno.",
|
||||
"EditSubtitles": "Editovat titulky",
|
||||
"UnlockGuide": "Pr\u016fvodce pro odem\u010den\u00ed",
|
||||
"RefreshMetadata": "Obnovit Metadata",
|
||||
"ReplaceExistingImages": "Nahradit existuj\u00edc\u00ed obr\u00e1zky",
|
||||
"ReplaceAllMetadata": "Replace all metadata",
|
||||
"SearchForMissingMetadata": "Search for missing metadata",
|
||||
"LabelRefreshMode": "Refresh mode:",
|
||||
"ReplaceAllMetadata": "P\u0159epsat v\u0161echna metadata",
|
||||
"SearchForMissingMetadata": "Hled\u00e1n\u00ed chyb\u011bj\u00edc\u00edch metadat",
|
||||
"LabelRefreshMode": "M\u00f3d obnovy:",
|
||||
"NoItemsFound": "Nenalezeny \u017e\u00e1dn\u00e9 polo\u017eky.",
|
||||
"HeaderSaySomethingLike": "Vyslovte n\u011bco jako...",
|
||||
"ButtonTryAgain": "Zkusit znovu",
|
||||
@ -110,35 +110,35 @@
|
||||
"Favorite": "Obl\u00edben\u00e9",
|
||||
"Like": "M\u00e1m r\u00e1d",
|
||||
"Dislike": "Nem\u00e1m r\u00e1d",
|
||||
"RefreshDialogHelp": "Metadata is refreshed based on settings and internet services that are enabled in the Emby Server dashboard.",
|
||||
"RefreshDialogHelp": "Metadata se aktualizuj\u00ed na z\u00e1klad\u011b nastaven\u00ed a internetov\u00fdch slu\u017eeb, kter\u00e9 jsou povoleny v nastaven\u00ed Emby Server.",
|
||||
"Open": "Otev\u0159\u00edt",
|
||||
"Play": "P\u0159ehr\u00e1t",
|
||||
"Queue": "Fronta",
|
||||
"Shuffle": "N\u00e1hodn\u011b",
|
||||
"Identify": "Identifikuj",
|
||||
"EditImages": "Editace obr\u00e1zk\u016f",
|
||||
"EditInfo": "Edit info",
|
||||
"Sync": "Sync",
|
||||
"EditInfo": "Editace info",
|
||||
"Sync": "Synchronizace",
|
||||
"InstantMix": "Okam\u017eit\u00e9 m\u00edch\u00e1n\u00ed",
|
||||
"ViewAlbum": "Zobrazit album",
|
||||
"ViewArtist": "Zobrazit \u00fam\u011blce",
|
||||
"QueueAllFromHere": "Za\u0159adit v\u0161e do fronty",
|
||||
"PlayAllFromHere": "P\u0159ehr\u00e1t v\u0161e odsud",
|
||||
"PlayFromBeginning": "Play from beginning",
|
||||
"ResumeAt": "Resume from {0}",
|
||||
"PlayFromBeginning": "P\u0159ehr\u00e1t od za\u010d\u00e1tku",
|
||||
"ResumeAt": "Obnovit p\u0159ehr\u00e1v\u00e1n\u00ed od {0}",
|
||||
"RemoveFromPlaylist": "Odebrat z playlistu",
|
||||
"RemoveFromCollection": "Remove from collection",
|
||||
"RemoveFromCollection": "Odebrat z kolekce",
|
||||
"Trailer": "Uk\u00e1zka\/trailer",
|
||||
"MarkPlayed": "Ozna\u010dit p\u0159ehran\u00e9",
|
||||
"MarkUnplayed": "Ozna\u010dit nep\u0159ehran\u00e9",
|
||||
"GroupVersions": "Group versions",
|
||||
"GroupVersions": "Skupinov\u00e9 verze",
|
||||
"PleaseSelectTwoItems": "Vyberte nejm\u00e9n\u011b dv\u011b polo\u017eky pros\u00edm.",
|
||||
"TryMultiSelect": "Vyzkou\u0161ej multi-v\u00fdb\u011br",
|
||||
"TryMultiSelectMessage": "Chcete-li upravit v\u00edce medi\u00e1ln\u00edch polo\u017eek, sta\u010d\u00ed kliknout a podr\u017eet na kter\u00e9mkoliv plak\u00e1tu. Pot\u00e9 m\u016f\u017eete vybrat v\u00edce polo\u017eek, kter\u00e9 chcete spravovat. Zkus to!",
|
||||
"HeaderConfirmRecordingCancellation": "Potvrzen\u00ed zru\u0161en\u00ed nahr\u00e1v\u00e1n\u00ed",
|
||||
"MessageConfirmRecordingCancellation": "Jste si jisti, \u017ee chcete zru\u0161it tuto nahr\u00e1vku?",
|
||||
"Error": "Chyba",
|
||||
"VoiceInput": "Voice Input",
|
||||
"VoiceInput": "Hlasov\u00fd vstup",
|
||||
"LabelContentType": "Typ obsahu:",
|
||||
"LabelPath": "Cesta k souboru:",
|
||||
"LabelTitle": "N\u00e1zev:",
|
||||
@ -183,16 +183,16 @@
|
||||
"LabelAirsAfterSeason": "Vys\u00edl\u00e1no po sez\u00f3n\u011b:",
|
||||
"LabelAirsBeforeEpisode": "Vys\u00edl\u00e1no p\u0159ed epizodou:",
|
||||
"HeaderExternalIds": "Extern\u00ed Id:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"HeaderDisplaySettings": "Nastaven\u00ed zobrazen\u00ed",
|
||||
"LabelTreatImageAs": "Pova\u017eovat obr\u00e1zek za:",
|
||||
"LabelDisplayOrder": "Po\u0159ad\u00ed zobrazen\u00ed:",
|
||||
"Countries": "Countries",
|
||||
"Genres": "Genres",
|
||||
"Countries": "Zem\u011b",
|
||||
"Genres": "\u017d\u00e1nry",
|
||||
"HeaderPlotKeywords": "Kl\u00ed\u010dov\u00e1 slova obsahu",
|
||||
"Studios": "Studios",
|
||||
"Studios": "Studia",
|
||||
"Tags": "Tagy",
|
||||
"HeaderMetadataSettings": "Nastaven\u00ed metadat",
|
||||
"People": "People",
|
||||
"People": "Lid\u00e9",
|
||||
"LabelMetadataDownloadLanguage": "Preferovan\u00fd jazyk:",
|
||||
"LabelLockItemToPreventChanges": "Uzamknout polo\u017eku pro z\u00e1branu budouc\u00edch zm\u011bn",
|
||||
"MessageLeaveEmptyToInherit": "P\u0159i ponech\u00e1n\u00ed pr\u00e1zdn\u00e9 polo\u017eky bude zd\u011bd\u011bno nastaven\u00ed z polo\u017eky p\u0159edka nebo z glob\u00e1ln\u00ed defaultn\u00ed hodnoty.",
|
||||
@ -202,14 +202,14 @@
|
||||
"LabelBirthDate": "Datum narozen\u00ed:",
|
||||
"LabelDeathDate": "Datum \u00famrt\u00ed:",
|
||||
"LabelEndDate": "Datum ukon\u010den\u00ed:",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelSeasonNumber": "\u010c\u00edslo sez\u00f3ny:",
|
||||
"LabelEpisodeNumber": "\u010c\u00edslo epizody:",
|
||||
"LabelTrackNumber": "\u010c\u00edslo stopy:",
|
||||
"LabelNumber": "\u010c\u00edslo:",
|
||||
"LabelDiscNumber": "\u010c\u00edslo disku",
|
||||
"LabelParentNumber": "\u010c\u00edslo p\u0159edch\u016fdce",
|
||||
"SortName": "Set\u0159\u00eddit dle n\u00e1zvu",
|
||||
"ReleaseDate": "Release date",
|
||||
"ReleaseDate": "Datum vyd\u00e1n\u00ed",
|
||||
"Continuing": "Pokra\u010dov\u00e1n\u00ed",
|
||||
"Ended": "Ukon\u010deno",
|
||||
"HeaderEnabledFields": "Povolen\u00e9 pole",
|
||||
@ -217,26 +217,26 @@
|
||||
"Backdrops": "Pozad\u00ed",
|
||||
"Images": "Obr\u00e1zky",
|
||||
"Keywords": "Kl\u00ed\u010dov\u00e1 slova",
|
||||
"Runtime": "Runtime",
|
||||
"ProductionLocations": "Production locations",
|
||||
"BirthLocation": "Birth location",
|
||||
"Runtime": "D\u00e9lka",
|
||||
"ProductionLocations": "M\u00edsto v\u00fdroby",
|
||||
"BirthLocation": "M\u00edsto narozen\u00ed",
|
||||
"ParentalRating": "Rodi\u010dovsk\u00e9 hodnocen\u00ed",
|
||||
"Name": "Name",
|
||||
"Overview": "Overview",
|
||||
"Name": "N\u00e1zev",
|
||||
"Overview": "P\u0159ehled\/Obsah",
|
||||
"LabelType": "Typ:",
|
||||
"LabelPersonRole": "Role:",
|
||||
"LabelPersonRoleHelp": "Example: Ice cream truck driver",
|
||||
"LabelPersonRoleHelp": "P\u0159\u00edklad: \u0158idi\u010d kami\u00f3nu se zmrzlinou",
|
||||
"Actor": "Herec",
|
||||
"Composer": "Skladatel",
|
||||
"Director": "Re\u017eis\u00e9r",
|
||||
"GuestStar": "Guest star",
|
||||
"GuestStar": "Hostuj\u00edc\u00ed hv\u011bzda",
|
||||
"Producer": "Producent",
|
||||
"Writer": "Napsal",
|
||||
"InstallingPackage": "Instalace {0}",
|
||||
"PackageInstallCompleted": "Instalace {0} dokon\u010dena.",
|
||||
"PackageInstallFailed": "Instalace {0} selhala!!!",
|
||||
"PackageInstallCancelled": "Instalace {0} zru\u0161ena.",
|
||||
"SeriesYearToPresent": "{0}-Sou\u010dasnost",
|
||||
"SeriesYearToPresent": "{0} - Sou\u010dasnost",
|
||||
"ValueOneSong": "1 song",
|
||||
"ValueSongCount": "{0} song\u016f",
|
||||
"ValueOneMovie": "1 film",
|
||||
@ -255,20 +255,20 @@
|
||||
"HeaderIdentifyItemHelp": "Zadejte jedno nebo v\u00edce vyhled\u00e1vac\u00edch krit\u00e9ri\u00ed. Odstra\u0148te krit\u00e9ria pro vyhled\u00e1n\u00ed v\u00edce v\u00fdsledk\u016f.",
|
||||
"PleaseEnterNameOrId": "Pros\u00edm, zadejte n\u00e1zev nebo extern\u00ed Id.",
|
||||
"MessageItemSaved": "Polo\u017eka ulo\u017eena.",
|
||||
"SearchResults": "Search Results",
|
||||
"SyncToOtherDevice": "Sync to other device",
|
||||
"MakeAvailableOffline": "Make available offline",
|
||||
"ServerNameIsRestarting": "Emby Server - {0} is restarting.",
|
||||
"ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.",
|
||||
"SearchResults": "V\u00fdsledky vyhled\u00e1v\u00e1n\u00ed",
|
||||
"SyncToOtherDevice": "Synchronizovat na dal\u0161\u00ed za\u0159\u00edzen\u00ed",
|
||||
"MakeAvailableOffline": "Zp\u0159\u00edstupnit offline",
|
||||
"ServerNameIsRestarting": "Emby Server - {0} je restartov\u00e1n.",
|
||||
"ServerNameIsShuttingDown": "Emby Server - {0} je vyp\u00edn\u00e1n.",
|
||||
"HeaderDeleteItems": "Odstranit polo\u017eky",
|
||||
"ConfirmDeleteItems": "Odstran\u011bn\u00edm t\u011bchto polo\u017eek odstran\u00edte va\u0161e m\u00e9dia jak z knihovny m\u00e9di\u00ed, tak i ze souborov\u00e9ho syst\u00e9mu. Jste si jisti, \u017ee chcete pokra\u010dovat?",
|
||||
"PleaseRestartServerName": "Please restart Emby Server - {0}.",
|
||||
"PleaseRestartServerName": "Pros\u00edm, restartujte Emby Server - {0}.",
|
||||
"SyncJobCreated": "\u00daloha Sync vytvo\u0159ena",
|
||||
"LabelSyncTo": "Sync do:",
|
||||
"LabelSyncJobName": "N\u00e1zev Sync \u00falohy:",
|
||||
"LabelQuality": "Kvalita:",
|
||||
"LabelSyncNoTargetsHelp": "Vypad\u00e1 to, \u017ee v sou\u010dasn\u00e9 dob\u011b nem\u00e1te \u017e\u00e1dn\u00e9 aplikace, kter\u00e9 podporuj\u00ed synchronizaci.",
|
||||
"DownloadScheduled": "Download scheduled",
|
||||
"DownloadScheduled": "Sta\u017een\u00ed napl\u00e1nov\u00e1no",
|
||||
"LearnMore": "Zjistit v\u00edce",
|
||||
"LabelProfile": "Profil:",
|
||||
"LabelBitrateMbps": "Datov\u00fd tok (Mbps):",
|
||||
@ -279,76 +279,80 @@
|
||||
"LabelItemLimit": "Limit polo\u017eek:",
|
||||
"LabelItemLimitHelp": "Voliteln\u00e9. Nastaven\u00ed limitu k po\u010dtu polo\u017eek, kter\u00e9 budou synchronizovan\u00e9.",
|
||||
"PleaseSelectDeviceToSyncTo": "Vyberte za\u0159\u00edzen\u00ed k synchronizaci.",
|
||||
"Screenshots": "Screenshots",
|
||||
"MoveRight": "Move right",
|
||||
"MoveLeft": "Move left",
|
||||
"ConfirmDeleteImage": "Delete image?",
|
||||
"HeaderEditImages": "Edit Images",
|
||||
"Screenshots": "Sn\u00edmky obrazovky",
|
||||
"MoveRight": "Posunout vpravo",
|
||||
"MoveLeft": "Posunout vlevo",
|
||||
"ConfirmDeleteImage": "Odstranit obr\u00e1zek?",
|
||||
"HeaderEditImages": "Editace obr\u00e1zk\u016f",
|
||||
"Settings": "Nastaven\u00ed",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
"NewEpisodes": "New episodes",
|
||||
"HDPrograms": "HD programs",
|
||||
"LiveBroadcasts": "Live broadcasts",
|
||||
"Premieres": "Premieres",
|
||||
"RepeatEpisodes": "Repeat episodes",
|
||||
"DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.",
|
||||
"HeaderCancelRecording": "Cancel Recording",
|
||||
"CancelRecording": "Cancel recording",
|
||||
"HeaderKeepRecording": "Keep Recording",
|
||||
"HeaderCancelSeries": "Cancel Series",
|
||||
"HeaderKeepSeries": "Keep Series",
|
||||
"HeaderLearnMore": "Learn More",
|
||||
"DeleteMedia": "Delete media",
|
||||
"SeriesSettings": "Series settings",
|
||||
"HeaderRecordingOptions": "Recording Options",
|
||||
"CancelSeries": "Cancel series",
|
||||
"DoNotRecord": "Do not record",
|
||||
"HeaderSeriesOptions": "Series Options",
|
||||
"LabelChannels": "Channels:",
|
||||
"ChannelNameOnly": "Channel {0} only",
|
||||
"Anytime": "Anytime",
|
||||
"AroundTime": "Around {0}",
|
||||
"LabelAirtime": "Airtime:",
|
||||
"AllChannels": "All channels",
|
||||
"LabelRecord": "Record:",
|
||||
"NewEpisodesOnly": "New episodes only",
|
||||
"AllEpisodes": "All episodes",
|
||||
"LabelStartWhenPossible": "Start when possible:",
|
||||
"LabelStopWhenPossible": "Stop when possible:",
|
||||
"MinutesBefore": "minutes before",
|
||||
"MinutesAfter": "minutes after",
|
||||
"SkipEpisodesAlreadyInMyLibrary": "Skip episodes that are already in my library",
|
||||
"SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.",
|
||||
"LabelKeepUpTo": "Keep up to:",
|
||||
"AsManyAsPossible": "As many as possible",
|
||||
"ShowIndicatorsFor": "Zobrazit indik\u00e1tor pro:",
|
||||
"NewEpisodes": "Nov\u00e9 episody",
|
||||
"HDPrograms": "HD programy",
|
||||
"LiveBroadcasts": "P\u0159\u00edm\u00e9 p\u0159enosy",
|
||||
"Premieres": "Premi\u00e9ry",
|
||||
"RepeatEpisodes": "Opakovan\u00ed epizod",
|
||||
"DvrSubscriptionRequired": "Emby DVR vy\u017eaduje aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere.",
|
||||
"HeaderCancelRecording": "Zru\u0161it nahr\u00e1v\u00e1n\u00ed",
|
||||
"CancelRecording": "Zru\u0161it nahr\u00e1v\u00e1n\u00ed",
|
||||
"HeaderKeepRecording": "Udr\u017eet nahr\u00e1v\u00e1n\u00ed",
|
||||
"HeaderCancelSeries": "Ukon\u010dit Seri\u00e1l",
|
||||
"HeaderKeepSeries": "Udr\u017eet seri\u00e1l",
|
||||
"HeaderLearnMore": "Zjistit v\u00edce",
|
||||
"DeleteMedia": "Odstranit m\u00e9dia",
|
||||
"SeriesSettings": "Nastaven\u00ed seri\u00e1lu",
|
||||
"HeaderRecordingOptions": "Nastaven\u00ed nahr\u00e1v\u00e1n\u00ed",
|
||||
"CancelSeries": "Ukon\u010dit Seri\u00e1l",
|
||||
"DoNotRecord": "Nenahr\u00e1vat",
|
||||
"HeaderSeriesOptions": "Nastaven\u00ed seri\u00e1lu",
|
||||
"LabelChannels": "Kan\u00e1ly:",
|
||||
"ChannelNameOnly": "Kan\u00e1l {0} jen",
|
||||
"Anytime": "Kdykoliv",
|
||||
"AroundTime": "Okolo {0}",
|
||||
"LabelAirtime": "\u010cas vys\u00edl\u00e1n\u00ed:",
|
||||
"AllChannels": "V\u0161echny kan\u00e1ly",
|
||||
"LabelRecord": "Z\u00e1znam:",
|
||||
"NewEpisodesOnly": "Jen nov\u00e9 epizody",
|
||||
"AllEpisodes": "V\u0161echny epizody",
|
||||
"LabelStartWhenPossible": "Za\u010d\u00edt jakmile je to mo\u017en\u00e9:",
|
||||
"LabelStopWhenPossible": "Zastavit jakmile je to mo\u017en\u00e9:",
|
||||
"MinutesBefore": "minut p\u0159edem",
|
||||
"MinutesAfter": "minut po",
|
||||
"SkipEpisodesAlreadyInMyLibrary": "P\u0159esko\u010dit epizody, kter\u00e9 jsou u\u017e v m\u00e9 knihovn\u011b",
|
||||
"SkipEpisodesAlreadyInMyLibraryHelp": "Epizody budou porovn\u00e1v\u00e1ny s pou\u017eit\u00edm obdob\u00ed a \u010d\u00edsla epizody, pokud jsou k dispozici.",
|
||||
"LabelKeepUpTo": "Aktualizovat k:",
|
||||
"AsManyAsPossible": "Tolikr\u00e1t jak je mo\u017en\u00e9",
|
||||
"DefaultErrorMessage": "Do\u0161lo k chyb\u011b p\u0159i zpracov\u00e1n\u00ed po\u017eadavku. Pros\u00edm zkuste to znovu pozd\u011bji.",
|
||||
"LabelKeep:": "Keep:",
|
||||
"UntilIDelete": "Until I delete",
|
||||
"UntilSpaceNeeded": "Until space needed",
|
||||
"Categories": "Categories",
|
||||
"Sports": "Sports",
|
||||
"News": "News",
|
||||
"Movies": "Movies",
|
||||
"Kids": "Kids",
|
||||
"EnableColorCodedBackgrounds": "Enable color coded backgrounds",
|
||||
"SortChannelsBy": "Sort channels by:",
|
||||
"RecentlyWatched": "Recently watched",
|
||||
"ChannelNumber": "Channel number",
|
||||
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.",
|
||||
"HeaderTryPlayback": "Try Playback",
|
||||
"HowDidYouPay": "How did you pay?",
|
||||
"IHaveEmbyPremiere": "I have Emby Premiere",
|
||||
"IPurchasedThisApp": "I purchased this app",
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"LabelKeep:": "Udr\u017eet:",
|
||||
"UntilIDelete": "Dokud nesma\u017eu",
|
||||
"UntilSpaceNeeded": "Do pot\u0159ebn\u00e9ho prostoru",
|
||||
"Categories": "Kategorie",
|
||||
"Sports": "Sport",
|
||||
"News": "Zpravodajstv\u00ed",
|
||||
"Movies": "Filmy",
|
||||
"Kids": "D\u011btsk\u00e9",
|
||||
"EnableColorCodedBackgrounds": "Aktivovat barevn\u011b ozna\u010den\u00e9 pozad\u00ed",
|
||||
"SortChannelsBy": "T\u0159\u00eddit kan\u00e1ly dle:",
|
||||
"RecentlyWatched": "Ned\u00e1vno shl\u00e9dnut\u00e9",
|
||||
"ChannelNumber": "\u010c\u00edslo kan\u00e1lu",
|
||||
"HeaderBenefitsEmbyPremiere": "V\u00fdhody Emby Premiere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Pros\u00edm u\u017eijte si jednu minutu p\u0159ehr\u00e1v\u00e1n\u00ed. D\u011bkujeme v\u00e1m za vyzkou\u0161en\u00ed Emby.",
|
||||
"HeaderTryPlayback": "Zkusit playback",
|
||||
"HowDidYouPay": "Jak chcete platit?",
|
||||
"IHaveEmbyPremiere": "Ji\u017e m\u00e1m Emby Premiere",
|
||||
"IPurchasedThisApp": "Tuto aplikaci m\u00e1m ji\u017e zaplacenu",
|
||||
"ButtonRestorePreviousPurchase": "Obnovit n\u00e1kup",
|
||||
"ButtonUnlockWithPurchase": "Odemkn\u011bte pomoc\u00ed koup\u011b",
|
||||
"ButtonUnlockPrice": "Odemknout {0}",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "P\u0159ehr\u00e1t jednu minutu",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Um\u00edstit obl\u00edben\u00e9 kan\u00e1ly na za\u010d\u00e1tek",
|
||||
"HeaderUnlockFeature": "Odemknout funkci",
|
||||
"MessageDidYouKnowCinemaMode": "V\u00edte, \u017ee s Emby Premiere m\u016f\u017eete zlep\u0161it sv\u00e9 z\u00e1\u017eitky ze sledov\u00e1n\u00ed pomoc\u00ed funkce jako Cinema M\u00f3d?",
|
||||
"MessageDidYouKnowCinemaMode2": "S re\u017eimem Kino budou p\u0159ed hlavn\u00edm programem p\u0159ehr\u00e1ny upout\u00e1vky a u\u017eivatelsk\u00e1 intra.",
|
||||
"HeaderPlayMyMedia": "P\u0159ehr\u00e1t moje M\u00e9dia",
|
||||
"HeaderDiscoverEmbyPremiere": "Objevte v\u00fdhody Emby Premiere",
|
||||
"OneChannel": "Jeden kan\u00e1l",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Ausstrahlungen vor Staffel:",
|
||||
"LabelAirsAfterSeason": "Ausstrahlungen nach Staffel:",
|
||||
"LabelAirsBeforeEpisode": "Ausstrahlungen vor Episode:",
|
||||
"HeaderExternalIds": "Externe Id's:",
|
||||
"HeaderExternalIds": "Externe IDs:",
|
||||
"HeaderDisplaySettings": "Anzeige Einstellungen",
|
||||
"LabelTreatImageAs": "Bild behandeln, wie:",
|
||||
"LabelDisplayOrder": "Anzeigereihenfolge:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Kauf wiederherstellen",
|
||||
"ButtonUnlockWithPurchase": "Freischalten durch Kauf",
|
||||
"ButtonUnlockPrice": "{0} freischalten",
|
||||
"ButtonAlreadyPaid": "Schon bezahlt?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monatlich {0}",
|
||||
"HeaderAlreadyPaid": "Schon bezahlt?",
|
||||
"ButtonPlayOneMinute": "Eine Minute wiedergeben",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Platziere favorisierte Kan\u00e4le am Anfang",
|
||||
"HeaderUnlockFeature": "Feature freischalten",
|
||||
"MessageDidYouKnowCinemaMode": "Wusstest du schon, das du mit Emby Premiere dein Erlebnis mit Funktionen wie dem Kino-Modus noch verbessern kannst?",
|
||||
"MessageDidYouKnowCinemaMode2": "Der Kino-Modus bringt das richtige Kino-Erlebnis nach Hause, mit Trailern und eigenen Intros vor deinem Hauptfilm.",
|
||||
"HeaderPlayMyMedia": "Spiele meine Medien ab",
|
||||
"HeaderDiscoverEmbyPremiere": "Entdecke Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Entdecke Emby Premiere",
|
||||
"OneChannel": "Ein Kanal",
|
||||
"ConfirmRemoveDownload": "Download entfernen?",
|
||||
"AddedOnValue": "Hinzugef\u00fcgt {0}"
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
{
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.",
|
||||
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.",
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "\u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03ba\u03b1\u03c4\u03b1\u03b2\u03ac\u03bb\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ad\u03bd\u03b1 \u03c0\u03bf\u03bb\u03cd \u03bc\u03b9\u03ba\u03c1\u03cc \u03ba\u03cc\u03c3\u03c4\u03bf\u03c2 \u03ae \u03bc\u03b5 \u03bc\u03af\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c4\u03bf Emby Premiere.",
|
||||
"MessageUnlockAppWithSupporter": "\u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03bc\u03b5 \u03bc\u03af\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c4\u03bf Emby Premiere.",
|
||||
"MessageToValidateSupporter": "If you have an active Emby Premiere subscription, ensure you've setup Emby Premiere in your Emby Server Dashboard, which you can access by clicking Emby Premiere within the main menu.",
|
||||
"ValueSpecialEpisodeName": "Special - {0}",
|
||||
"Share": "Share",
|
||||
"Add": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5",
|
||||
"ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}",
|
||||
"LiveTvGuideRequiresUnlock": "The Live TV Guide is currently limited to {0} channels. Click the unlock button to learn how to enjoy the full experience.",
|
||||
"AttributeNew": "New",
|
||||
"AttributeNew": "\u039d\u03ad\u03bf",
|
||||
"Premiere": "Premiere",
|
||||
"Live": "Live",
|
||||
"Repeat": "Repeat",
|
||||
"Live": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ac",
|
||||
"Repeat": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7",
|
||||
"TrackCount": "{0} tracks",
|
||||
"ItemCount": "{0} items",
|
||||
"ReleaseYearValue": "Release year: {0}",
|
||||
"ReleaseYearValue": "\u0388\u03c4\u03bf\u03c2 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2: {0} \n",
|
||||
"OriginalAirDateValue": "Original air date: {0}",
|
||||
"EndsAtValue": "Ends at {0}",
|
||||
"OptionSundayShort": "Sun",
|
||||
"OptionMondayShort": "Mon",
|
||||
"OptionTuesdayShort": "Tue",
|
||||
"OptionWednesdayShort": "Wed",
|
||||
"OptionThursdayShort": "Thu",
|
||||
"OptionFridayShort": "Fri",
|
||||
"OptionSaturdayShort": "Sat",
|
||||
"HeaderSelectDate": "Select Date",
|
||||
"OptionSundayShort": "\u039a\u03c5\u03c1",
|
||||
"OptionMondayShort": "\u0394\u03b5\u03c5",
|
||||
"OptionTuesdayShort": "\u03a4\u03c1\u03b9",
|
||||
"OptionWednesdayShort": "\u03a4\u03b5\u03c4",
|
||||
"OptionThursdayShort": "\u03a0\u03b5\u03bc",
|
||||
"OptionFridayShort": "\u03a0\u03b1\u03c1",
|
||||
"OptionSaturdayShort": "\u03a3\u03b1\u03b2",
|
||||
"HeaderSelectDate": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1\u03c2",
|
||||
"ButtonOk": "Ok",
|
||||
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
|
||||
"ButtonGotIt": "Got It",
|
||||
"ButtonRestart": "Restart",
|
||||
"ButtonRestart": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
|
||||
"RecordingCancelled": "Recording cancelled.",
|
||||
"SeriesCancelled": "Series cancelled.",
|
||||
"RecordingScheduled": "Recording scheduled.",
|
||||
"SeriesRecordingScheduled": "Series recording scheduled.",
|
||||
"HeaderNewRecording": "New Recording",
|
||||
"Sunday": "Sunday",
|
||||
"Monday": "Monday",
|
||||
"Tuesday": "Tuesday",
|
||||
"Wednesday": "Wednesday",
|
||||
"Thursday": "Thursday",
|
||||
"Friday": "Friday",
|
||||
"Saturday": "Saturday",
|
||||
"Days": "Days",
|
||||
"HeaderNewRecording": "\u039d\u03ad\u03b1 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae",
|
||||
"Sunday": "\u039a\u03c5\u03c1\u03b9\u03b1\u03ba\u03ae",
|
||||
"Monday": "\u0394\u03b5\u03c5\u03c4\u03ad\u03c1\u03b1",
|
||||
"Tuesday": "\u03a4\u03c1\u03af\u03c4\u03b7",
|
||||
"Wednesday": "\u03a4\u03b5\u03c4\u03ac\u03c1\u03c4\u03b7",
|
||||
"Thursday": "\u03a0\u03ad\u03bc\u03c0\u03c4\u03b7",
|
||||
"Friday": "\u03a0\u03b1\u03c1\u03b1\u03c3\u03ba\u03b5\u03c5\u03ae",
|
||||
"Saturday": "\u03a3\u03ac\u03b2\u03b2\u03b1\u03c4\u03bf",
|
||||
"Days": "\u0397\u03bc\u03ad\u03c1\u03b5\u03c2",
|
||||
"RecordSeries": "Record series",
|
||||
"HeaderCinemaMode": "Cinema Mode",
|
||||
"HeaderCloudSync": "Cloud Sync",
|
||||
@ -50,52 +50,52 @@
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
|
||||
"CoverArt": "Cover Art",
|
||||
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
|
||||
"HeaderFreeApps": "Free Emby Apps",
|
||||
"HeaderFreeApps": "\u0394\u03c9\u03c1\u03b5\u03ac\u03bd \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 Emby",
|
||||
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.",
|
||||
"HeaderBecomeProjectSupporter": "Get Emby Premiere",
|
||||
"HeaderBecomeProjectSupporter": "\u0391\u03c0\u03cc\u03ba\u03c4\u03b7\u03c3\u03b5 \u03a3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere",
|
||||
"MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.",
|
||||
"LabelEmailAddress": "E-mail address:",
|
||||
"LabelEmailAddress": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 E-mail",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Emby Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Emby server settings.",
|
||||
"FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.",
|
||||
"HeaderConvertYourRecordings": "Convert Your Recordings",
|
||||
"Record": "Record",
|
||||
"Record": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae",
|
||||
"Save": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7",
|
||||
"Edit": "Edit",
|
||||
"Edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1",
|
||||
"Download": "Download",
|
||||
"Advanced": "Advanced",
|
||||
"Delete": "Delete",
|
||||
"HeaderDeleteItem": "Delete Item",
|
||||
"Delete": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae",
|
||||
"HeaderDeleteItem": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u0391\u03bd\u03c4\u03b9\u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5",
|
||||
"ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
|
||||
"Refresh": "Refresh",
|
||||
"Refresh": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7",
|
||||
"RefreshQueued": "Refresh queued.",
|
||||
"AddToCollection": "Add to collection",
|
||||
"AddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
|
||||
"HeaderAddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
|
||||
"NewCollection": "New Collection",
|
||||
"LabelCollection": "Collection:",
|
||||
"NewCollection": "\u039d\u03ad\u03b1 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
|
||||
"LabelCollection": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae:",
|
||||
"Help": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1",
|
||||
"NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.",
|
||||
"SearchForCollectionInternetMetadata": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03b3\u03b9\u03b1 \u03b5\u03be\u03ce\u03c6\u03c5\u03bb\u03bb\u03bf \u03ba\u03b1\u03b9 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2",
|
||||
"LabelName": "\u038c\u03bd\u03bf\u03bc\u03b1:",
|
||||
"NewCollectionNameExample": "\u03a0\u03b1\u03c1\u03ac\u03b4\u03b5\u03b9\u03b3\u03bc\u03b1: \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae \"\u03a0\u03cc\u03bb\u03b5\u03bc\u03bf\u03c2 \u03c4\u03c9\u03bd \u0386\u03c3\u03c4\u03c1\u03c9\u03bd\"",
|
||||
"MessageItemsAdded": "Items added.",
|
||||
"OptionNew": "New...",
|
||||
"LabelPlaylist": "Playlist:",
|
||||
"AddToPlaylist": "Add to playlist",
|
||||
"HeaderAddToPlaylist": "Add to Playlist",
|
||||
"Subtitles": "Subtitles",
|
||||
"SearchForSubtitles": "Search for Subtitles",
|
||||
"OptionNew": "\u039d\u03ad\u03bf...",
|
||||
"LabelPlaylist": "\u039b\u03af\u03c3\u03c4\u03b1:",
|
||||
"AddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u03bb\u03af\u03c3\u03c4\u03b1",
|
||||
"HeaderAddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u039b\u03af\u03c3\u03c4\u03b1",
|
||||
"Subtitles": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9",
|
||||
"SearchForSubtitles": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03a5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd",
|
||||
"LabelLanguage": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1",
|
||||
"Search": "Search",
|
||||
"Search": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7",
|
||||
"NoSubtitleSearchResultsFound": "No results found.",
|
||||
"File": "File",
|
||||
"MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
|
||||
"ConfirmDeletion": "Confirm Deletion",
|
||||
"MySubtitles": "My Subtitles",
|
||||
"ConfirmDeletion": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03af\u03c9\u03c3\u03b7 \u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2",
|
||||
"MySubtitles": "\u039f\u03b9 \u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03bc\u03bf\u03c5",
|
||||
"MessageDownloadQueued": "Download queued.",
|
||||
"EditSubtitles": "Edit subtitles",
|
||||
"EditSubtitles": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd",
|
||||
"UnlockGuide": "Unlock Guide",
|
||||
"RefreshMetadata": "Refresh Metadata",
|
||||
"ReplaceExistingImages": "Replace existing images",
|
||||
"RefreshMetadata": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7 \u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd",
|
||||
"ReplaceExistingImages": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03c3\u03c9\u03bd \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd",
|
||||
"ReplaceAllMetadata": "Replace all metadata",
|
||||
"SearchForMissingMetadata": "Search for missing metadata",
|
||||
"LabelRefreshMode": "Refresh mode:",
|
||||
@ -139,7 +139,7 @@
|
||||
"MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?",
|
||||
"Error": "Error",
|
||||
"VoiceInput": "Voice Input",
|
||||
"LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd:",
|
||||
"LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5:",
|
||||
"LabelPath": "Path:",
|
||||
"LabelTitle": "Title:",
|
||||
"LabelOriginalTitle": "Original title:",
|
||||
@ -147,7 +147,7 @@
|
||||
"LabelDateAdded": "Date added:",
|
||||
"ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings",
|
||||
"LabelStatus": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7:",
|
||||
"LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
|
||||
"LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2:",
|
||||
"LabelArtistsHelp": "Separate multiple using ;",
|
||||
"LabelAlbumArtists": "Album artists:",
|
||||
"LabelAlbum": "Album:",
|
||||
@ -162,7 +162,7 @@
|
||||
"LabelOverview": "Overview:",
|
||||
"LabelShortOverview": "Short overview:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelYear": "\u0388\u03c4\u03bf\u03c2:",
|
||||
"LabelPlaceOfBirth": "Place of birth:",
|
||||
"LabelAirDays": "Air days:",
|
||||
"LabelAirTime": "Air time:",
|
||||
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -196,7 +196,7 @@
|
||||
"LabelMetadataDownloadLanguage": "Preferred download language:",
|
||||
"LabelLockItemToPreventChanges": "Lock this item to prevent future changes",
|
||||
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.",
|
||||
"LabelCountry": "\u03a7\u03ce\u03c1\u03b1",
|
||||
"LabelCountry": "\u03a7\u03ce\u03c1\u03b1:",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelBirthDate": "Birth date:",
|
||||
@ -220,7 +220,7 @@
|
||||
"Runtime": "Runtime",
|
||||
"ProductionLocations": "Production locations",
|
||||
"BirthLocation": "Birth location",
|
||||
"ParentalRating": "Parental Rating",
|
||||
"ParentalRating": "\u039a\u03b1\u03c4\u03b1\u03bb\u03bb\u03b7\u03bb\u03cc\u03c4\u03b7\u03c4\u03b1",
|
||||
"Name": "Name",
|
||||
"Overview": "Overview",
|
||||
"LabelType": "Type:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -47,7 +47,7 @@
|
||||
"HeaderOfflineDownloads": "Offline Media",
|
||||
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.",
|
||||
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.",
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalise your media images.",
|
||||
"CoverArt": "Cover Art",
|
||||
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
|
||||
"HeaderFreeApps": "Free Emby Apps",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favourite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Transmisi\u00f3n antes de la temporada:",
|
||||
"LabelAirsAfterSeason": "Transmisi\u00f3n despu\u00e9s de la temporada:",
|
||||
"LabelAirsBeforeEpisode": "Transmisi\u00f3n antes del episodio:",
|
||||
"HeaderExternalIds": "Id\u00b4s Externos:",
|
||||
"HeaderExternalIds": "IDs Externos:",
|
||||
"HeaderDisplaySettings": "Configuraci\u00f3n de Pantalla",
|
||||
"LabelTreatImageAs": "Tratar imagen como:",
|
||||
"LabelDisplayOrder": "Orden para mostrar:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restaurar Compra",
|
||||
"ButtonUnlockWithPurchase": "Desbloquear con una Compra",
|
||||
"ButtonUnlockPrice": "Desbloquear {0}",
|
||||
"ButtonAlreadyPaid": "\u00bfYa esta pagado?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premier Mensual {0}",
|
||||
"HeaderAlreadyPaid": "\u00bfYa ha pagado?",
|
||||
"ButtonPlayOneMinute": "Reproducir un minuto",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Colocar canales favoritos al inicio",
|
||||
"HeaderUnlockFeature": "Desbloquear Caracter\u00edstica",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"MessageDidYouKnowCinemaMode": "\u00bfSab\u00eda que con Emby Premier, puede mejorar su experiencia con caracter\u00edsticas como Modo Cine?",
|
||||
"MessageDidYouKnowCinemaMode2": "El Modo Cine le da una verdadera experiencia de cine con trailers e intros personalizados antes de la presentaci\u00f3n estelar.",
|
||||
"HeaderPlayMyMedia": "Reproducir mis Medios",
|
||||
"HeaderDiscoverEmbyPremiere": "Descubra Emby Premier",
|
||||
"OneChannel": "Un canal",
|
||||
"ConfirmRemoveDownload": "\u00bfEliminar descarga?",
|
||||
"AddedOnValue": "Agregado {0}"
|
||||
}
|
@ -29,7 +29,7 @@
|
||||
"ButtonGotIt": "Lo tengo",
|
||||
"ButtonRestart": "Reiniciar",
|
||||
"RecordingCancelled": "Grabaci\u00f3n cancelada.",
|
||||
"SeriesCancelled": "Series cancelled.",
|
||||
"SeriesCancelled": "Series cancelada.",
|
||||
"RecordingScheduled": "Grabaci\u00f3n programada.",
|
||||
"SeriesRecordingScheduled": "Series recording scheduled.",
|
||||
"HeaderNewRecording": "Nueva grabaci\u00f3n",
|
||||
@ -117,8 +117,8 @@
|
||||
"Shuffle": "Mezclar",
|
||||
"Identify": "Identificar",
|
||||
"EditImages": "Editar im\u00e1genes",
|
||||
"EditInfo": "Edit info",
|
||||
"Sync": "Sync",
|
||||
"EditInfo": "Editar info",
|
||||
"Sync": "Sincronizar",
|
||||
"InstantMix": "Mix instant\u00e1neo",
|
||||
"ViewAlbum": "Ver album",
|
||||
"ViewArtist": "Ver artista",
|
||||
@ -141,8 +141,8 @@
|
||||
"VoiceInput": "Voice Input",
|
||||
"LabelContentType": "Tipo de contenido:",
|
||||
"LabelPath": "Ruta:",
|
||||
"LabelTitle": "Title:",
|
||||
"LabelOriginalTitle": "Original title:",
|
||||
"LabelTitle": "T\u00edtulo",
|
||||
"LabelOriginalTitle": "T\u00edtulo original",
|
||||
"LabelSortTitle": "Sort title:",
|
||||
"LabelDateAdded": "Fecha a\u00f1adido:",
|
||||
"ConfigureDateAdded": "Configura como la fecha a\u00f1adida se determina en el Panel de Control del servidor Emby en los ajustes de la biblioteca.",
|
||||
@ -162,7 +162,7 @@
|
||||
"LabelOverview": "Resumen:",
|
||||
"LabelShortOverview": "Resumen corto:",
|
||||
"LabelReleaseDate": "Fecha de lanzamiento:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelYear": "A\u00f1o:",
|
||||
"LabelPlaceOfBirth": "Lugar de nacimiento:",
|
||||
"LabelAirDays": "D\u00edas de emisi\u00f3n:",
|
||||
"LabelAirTime": "Tiempo de emisi\u00f3n:",
|
||||
@ -186,13 +186,13 @@
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Tratar imagen como:",
|
||||
"LabelDisplayOrder": "Mostrar orden:",
|
||||
"Countries": "Countries",
|
||||
"Genres": "Genres",
|
||||
"Countries": "Pa\u00edses",
|
||||
"Genres": "G\u00e9neros",
|
||||
"HeaderPlotKeywords": "Palabras clave del reparto",
|
||||
"Studios": "Studios",
|
||||
"Studios": "Estudios",
|
||||
"Tags": "Etiquetas",
|
||||
"HeaderMetadataSettings": "Ajustes de metadatos",
|
||||
"People": "People",
|
||||
"People": "Gente",
|
||||
"LabelMetadataDownloadLanguage": "Idioma preferido visualizado",
|
||||
"LabelLockItemToPreventChanges": "Bloquear este \u00edtem para evitar futuros cambios",
|
||||
"MessageLeaveEmptyToInherit": "Dejar en blanco para heredar la configuraci\u00f3n de un elemento principal, o el valor predeterminado global.",
|
||||
@ -209,7 +209,7 @@
|
||||
"LabelDiscNumber": "N\u00famero de disco",
|
||||
"LabelParentNumber": "N\u00famero de los padres",
|
||||
"SortName": "Ordenar por nombre",
|
||||
"ReleaseDate": "Release date",
|
||||
"ReleaseDate": "Fecha de lanzamiento",
|
||||
"Continuing": "Continuando",
|
||||
"Ended": "Finalizado",
|
||||
"HeaderEnabledFields": "Campos activados",
|
||||
@ -221,7 +221,7 @@
|
||||
"ProductionLocations": "Production locations",
|
||||
"BirthLocation": "Birth location",
|
||||
"ParentalRating": "Parental Rating",
|
||||
"Name": "Name",
|
||||
"Name": "Nombre",
|
||||
"Overview": "Overview",
|
||||
"LabelType": "Tipo:",
|
||||
"LabelPersonRole": "Rol:",
|
||||
@ -229,7 +229,7 @@
|
||||
"Actor": "Actor",
|
||||
"Composer": "Compositor",
|
||||
"Director": "Director",
|
||||
"GuestStar": "Guest star",
|
||||
"GuestStar": "Estrella invitada",
|
||||
"Producer": "Productor",
|
||||
"Writer": "Escritor",
|
||||
"InstallingPackage": "Instalando {0}",
|
||||
@ -279,11 +279,11 @@
|
||||
"LabelItemLimit": "L\u00edmite de \u00edtems:",
|
||||
"LabelItemLimitHelp": "Opcional. Pon un l\u00edmite de cantidad de \u00edtems que se sincronizar\u00e1n.",
|
||||
"PleaseSelectDeviceToSyncTo": "Por favor selecciona el dispositivo donde quieres sincronizar.",
|
||||
"Screenshots": "Screenshots",
|
||||
"MoveRight": "Move right",
|
||||
"MoveLeft": "Move left",
|
||||
"ConfirmDeleteImage": "Delete image?",
|
||||
"HeaderEditImages": "Edit Images",
|
||||
"Screenshots": "Capturas de pantalla",
|
||||
"MoveRight": "Mover derecha",
|
||||
"MoveLeft": "Mover izquierda",
|
||||
"ConfirmDeleteImage": "Borrar imagen",
|
||||
"HeaderEditImages": "Editar Im\u00e1genes",
|
||||
"Settings": "Ajustes",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
"NewEpisodes": "New episodes",
|
||||
@ -295,7 +295,7 @@
|
||||
"HeaderCancelRecording": "Cancel Recording",
|
||||
"CancelRecording": "Cancel recording",
|
||||
"HeaderKeepRecording": "Keep Recording",
|
||||
"HeaderCancelSeries": "Cancel Series",
|
||||
"HeaderCancelSeries": "Cancelar Series",
|
||||
"HeaderKeepSeries": "Keep Series",
|
||||
"HeaderLearnMore": "Learn More",
|
||||
"DeleteMedia": "Delete media",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Reproducir un minuto",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.",
|
||||
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.",
|
||||
"MessageToValidateSupporter": "If you have an active Emby Premiere subscription, ensure you've setup Emby Premiere in your Emby Server Dashboard, which you can access by clicking Emby Premiere within the main menu.",
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un petit achat en une fois, ou avec une souscription Emby Premiere.",
|
||||
"MessageUnlockAppWithSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec une souscription Emby Premiere.",
|
||||
"MessageToValidateSupporter": "Si vous avez un abonnement Emby Premiere, veuillez-vous assurer que vous avez configur\u00e9 Emby Premiere dans votre menu de gestion Emby Server auquel vous pouvez acc\u00e9der en cliquant sur Emby Premiere dans le menu principal",
|
||||
"ValueSpecialEpisodeName": "Sp\u00e9cial - {0}",
|
||||
"Share": "Partager",
|
||||
"Add": "Ajouter",
|
||||
@ -29,7 +29,7 @@
|
||||
"ButtonGotIt": "Vu",
|
||||
"ButtonRestart": "Red\u00e9marrer",
|
||||
"RecordingCancelled": "Enregistrement annul\u00e9.",
|
||||
"SeriesCancelled": "Series cancelled.",
|
||||
"SeriesCancelled": "S\u00e9rie annul\u00e9e.",
|
||||
"RecordingScheduled": "Enregistrement planifi\u00e9.",
|
||||
"SeriesRecordingScheduled": "Enregistrement de la s\u00e9rie pr\u00e9vue.",
|
||||
"HeaderNewRecording": "Nouvel enregistrement",
|
||||
@ -42,22 +42,22 @@
|
||||
"Saturday": "Samedi",
|
||||
"Days": "Jours",
|
||||
"RecordSeries": "Enregistrer s\u00e9ries",
|
||||
"HeaderCinemaMode": "Cinema Mode",
|
||||
"HeaderCloudSync": "Cloud Sync",
|
||||
"HeaderOfflineDownloads": "Offline Media",
|
||||
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.",
|
||||
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.",
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
|
||||
"CoverArt": "Cover Art",
|
||||
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
|
||||
"HeaderFreeApps": "Free Emby Apps",
|
||||
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.",
|
||||
"HeaderCinemaMode": "Mode Cin\u00e9ma",
|
||||
"HeaderCloudSync": "Synchronisation avec le cloud",
|
||||
"HeaderOfflineDownloads": "Contenu multim\u00e9dia hors-ligne",
|
||||
"HeaderOfflineDownloadsDescription": "T\u00e9l\u00e9chargez votre contenu multim\u00e9dia vers vos appareils pour une meilleure utilisation hors-ligne.",
|
||||
"CloudSyncFeatureDescription": "Synchronisez votre contenu multim\u00e9dia vers le cloud pour le sauvegarder, l'archiver et le convertir plus facilement.",
|
||||
"CoverArtFeatureDescription": "Pochette cr\u00e9\u00e9 des couvertures amusantes et d'autres fonctions pour vous aider \u00e0 personnaliser les pochettes de votre contenu multim\u00e9dia.",
|
||||
"CoverArt": "Pochette",
|
||||
"CinemaModeFeatureDescription": "Le Mode Cin\u00e9ma vous donne une v\u00e9ritable exp\u00e9rience cin\u00e9matique avec des trailers et des intros personnalis\u00e9es avant la lecture du contenu.",
|
||||
"HeaderFreeApps": "Apps Emby gratuites",
|
||||
"FreeAppsFeatureDescription": "Profitez d'un acc\u00e8s gratuit \u00e0 certaines applications Emby pour vos appareils.",
|
||||
"HeaderBecomeProjectSupporter": "Obtenez Emby Premiere",
|
||||
"MessageActiveSubscriptionRequiredSeriesRecordings": "Une souscription Emby Premiere active est n\u00e9cessaire pour cr\u00e9er des enregistrements automatiques de s\u00e9ries.",
|
||||
"LabelEmailAddress": "E-mail address:",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Emby Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Emby server settings.",
|
||||
"LabelEmailAddress": "Adresse mail:",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Convertissez automatiquement vos enregistrement en un format compatible streaming avec Emby Premiere. Les enregistrements seront convertis sur demande vers des formats MP4 ou MKV, selon les options du serveur Emby.",
|
||||
"FeatureRequiresEmbyPremiere": "Cette fonctionnalit\u00e9 requiert un compte Emby Premiere.",
|
||||
"HeaderConvertYourRecordings": "Convert Your Recordings",
|
||||
"HeaderConvertYourRecordings": "Convertissez Vos Enregistrements",
|
||||
"Record": "Enregistrer",
|
||||
"Save": "Sauvegarder",
|
||||
"Edit": "Modifier",
|
||||
@ -236,13 +236,13 @@
|
||||
"PackageInstallCompleted": "L'installation de {0} est termin\u00e9e.",
|
||||
"PackageInstallFailed": "L'installation de {0} a \u00e9chou\u00e9.",
|
||||
"PackageInstallCancelled": "L'installation de {0} a \u00e9t\u00e9 annul\u00e9e.",
|
||||
"SeriesYearToPresent": "{0}-Pr\u00e9sent",
|
||||
"SeriesYearToPresent": "{0} - Pr\u00e9sent",
|
||||
"ValueOneSong": "1 chanson",
|
||||
"ValueSongCount": "{0} chansons",
|
||||
"ValueOneMovie": "1 Film",
|
||||
"ValueMovieCount": "{0} films",
|
||||
"ValueOneSeries": "1 S\u00e9rie",
|
||||
"ValueSeriesCount": "{0} series",
|
||||
"ValueSeriesCount": "{0} s\u00e9ries",
|
||||
"ValueOneEpisode": "1 \u00e9pisode",
|
||||
"ValueEpisodeCount": "{0} \u00e9pisodes",
|
||||
"ValueOneGame": "1 jeu",
|
||||
@ -285,70 +285,74 @@
|
||||
"ConfirmDeleteImage": "Supprimer l'image ?",
|
||||
"HeaderEditImages": "Modifier les images",
|
||||
"Settings": "Param\u00e8tres",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
"NewEpisodes": "New episodes",
|
||||
"HDPrograms": "HD programs",
|
||||
"LiveBroadcasts": "Live broadcasts",
|
||||
"Premieres": "Premieres",
|
||||
"RepeatEpisodes": "Repeat episodes",
|
||||
"DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.",
|
||||
"HeaderCancelRecording": "Cancel Recording",
|
||||
"CancelRecording": "Cancel recording",
|
||||
"HeaderKeepRecording": "Keep Recording",
|
||||
"HeaderCancelSeries": "Cancel Series",
|
||||
"HeaderKeepSeries": "Keep Series",
|
||||
"HeaderLearnMore": "Learn More",
|
||||
"DeleteMedia": "Delete media",
|
||||
"SeriesSettings": "Series settings",
|
||||
"HeaderRecordingOptions": "Recording Options",
|
||||
"CancelSeries": "Cancel series",
|
||||
"DoNotRecord": "Do not record",
|
||||
"HeaderSeriesOptions": "Series Options",
|
||||
"LabelChannels": "Channels:",
|
||||
"ChannelNameOnly": "Channel {0} only",
|
||||
"Anytime": "Anytime",
|
||||
"AroundTime": "Around {0}",
|
||||
"LabelAirtime": "Airtime:",
|
||||
"AllChannels": "All channels",
|
||||
"LabelRecord": "Record:",
|
||||
"NewEpisodesOnly": "New episodes only",
|
||||
"AllEpisodes": "All episodes",
|
||||
"LabelStartWhenPossible": "Start when possible:",
|
||||
"LabelStopWhenPossible": "Stop when possible:",
|
||||
"MinutesBefore": "minutes before",
|
||||
"MinutesAfter": "minutes after",
|
||||
"SkipEpisodesAlreadyInMyLibrary": "Skip episodes that are already in my library",
|
||||
"SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.",
|
||||
"LabelKeepUpTo": "Keep up to:",
|
||||
"AsManyAsPossible": "As many as possible",
|
||||
"ShowIndicatorsFor": "Montrer les indicateurs pour:",
|
||||
"NewEpisodes": "Nouveaux \u00e9pisodes",
|
||||
"HDPrograms": "Programmes HD",
|
||||
"LiveBroadcasts": "Diffusions en direct",
|
||||
"Premieres": "Premi\u00e8res",
|
||||
"RepeatEpisodes": "R\u00e9p\u00e9ter les \u00e9pisodes",
|
||||
"DvrSubscriptionRequired": "Emby DVR n\u00e9cessite un abonnement \u00e0 Emby Premiere.",
|
||||
"HeaderCancelRecording": "Annuler l'enregistrement",
|
||||
"CancelRecording": "Annuler l'enregistrement",
|
||||
"HeaderKeepRecording": "Garder l'enregistrement",
|
||||
"HeaderCancelSeries": "Annuler la s\u00e9rie",
|
||||
"HeaderKeepSeries": "Garder la s\u00e9rie",
|
||||
"HeaderLearnMore": "En savoir plus",
|
||||
"DeleteMedia": "Effacer cet objet",
|
||||
"SeriesSettings": "Configuration de la s\u00e9rie",
|
||||
"HeaderRecordingOptions": "Options d'enregistrement",
|
||||
"CancelSeries": "Annuler la s\u00e9rie",
|
||||
"DoNotRecord": "Ne pas enregistrer",
|
||||
"HeaderSeriesOptions": "Options de la s\u00e9rie",
|
||||
"LabelChannels": "Cha\u00eenes:",
|
||||
"ChannelNameOnly": "Cha\u00eene {0} seulement",
|
||||
"Anytime": "N'importe quand",
|
||||
"AroundTime": "Vers {0}",
|
||||
"LabelAirtime": "Temps d'antenne:",
|
||||
"AllChannels": "Toutes les cha\u00eenes",
|
||||
"LabelRecord": "Enregistrer:",
|
||||
"NewEpisodesOnly": "Uniquement les nouveaux \u00e9pisodes",
|
||||
"AllEpisodes": "Tous les \u00e9pisodes",
|
||||
"LabelStartWhenPossible": "Commencer d\u00e8s que possible:",
|
||||
"LabelStopWhenPossible": "Arr\u00eater d\u00e8s que possible:",
|
||||
"MinutesBefore": "minutes avant",
|
||||
"MinutesAfter": "minutes apr\u00e8s",
|
||||
"SkipEpisodesAlreadyInMyLibrary": "Ne pas lire les \u00e9pisodes d\u00e9j\u00e0 pr\u00e9sents dans ma m\u00e9diath\u00e8que",
|
||||
"SkipEpisodesAlreadyInMyLibraryHelp": "Les \u00e9pisodes seront compar\u00e9s selon leurs saisons et num\u00e9ros d'\u00e9pisodes, si possible.",
|
||||
"LabelKeepUpTo": "Garder jusqu'\u00e0:",
|
||||
"AsManyAsPossible": "Autant que possible",
|
||||
"DefaultErrorMessage": "Il y a eu une erreur lors de l'ex\u00e9cution de la requ\u00eate. Veuillez r\u00e9essayer plus tard.",
|
||||
"LabelKeep:": "Keep:",
|
||||
"UntilIDelete": "Until I delete",
|
||||
"UntilSpaceNeeded": "Until space needed",
|
||||
"Categories": "Categories",
|
||||
"LabelKeep:": "Garder:",
|
||||
"UntilIDelete": "Jusqu'\u00e0 ce que je le supprime",
|
||||
"UntilSpaceNeeded": "Jusqu'\u00e0 ce que l'espace disque est n\u00e9cessaire",
|
||||
"Categories": "Cat\u00e9gories",
|
||||
"Sports": "Sports",
|
||||
"News": "News",
|
||||
"Movies": "Movies",
|
||||
"Kids": "Kids",
|
||||
"EnableColorCodedBackgrounds": "Enable color coded backgrounds",
|
||||
"SortChannelsBy": "Sort channels by:",
|
||||
"RecentlyWatched": "Recently watched",
|
||||
"ChannelNumber": "Channel number",
|
||||
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.",
|
||||
"HeaderTryPlayback": "Try Playback",
|
||||
"HowDidYouPay": "How did you pay?",
|
||||
"IHaveEmbyPremiere": "I have Emby Premiere",
|
||||
"IPurchasedThisApp": "I purchased this app",
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"News": "Actualit\u00e9s",
|
||||
"Movies": "Films",
|
||||
"Kids": "Enfants",
|
||||
"EnableColorCodedBackgrounds": "Activer les arri\u00e8res-plans \u00e0 code-couleur",
|
||||
"SortChannelsBy": "Trier les cha\u00eenes par:",
|
||||
"RecentlyWatched": "Lus r\u00e9cemment",
|
||||
"ChannelNumber": "Num\u00e9ro de cha\u00eene",
|
||||
"HeaderBenefitsEmbyPremiere": "Avantages de Emby Premiere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Profitez d'une minute de lecture. Merci d'avoir essay\u00e9 Emby.",
|
||||
"HeaderTryPlayback": "Essayer la lecture",
|
||||
"HowDidYouPay": "Comment avez-vous pay\u00e9?",
|
||||
"IHaveEmbyPremiere": "J'ai Emby Premiere",
|
||||
"IPurchasedThisApp": "J'ai achet\u00e9 cette application",
|
||||
"ButtonRestorePreviousPurchase": "Restaurer l'achat",
|
||||
"ButtonUnlockWithPurchase": "D\u00e9verrouillez par un achat.",
|
||||
"ButtonUnlockPrice": "D\u00e9verrouiller {0}",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Lire une minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Mettre vos cha\u00eenes pr\u00e9f\u00e9r\u00e9es au d\u00e9but",
|
||||
"HeaderUnlockFeature": "D\u00e9verrouiller la fonction",
|
||||
"MessageDidYouKnowCinemaMode": "Saviez-vous qu'avec Emby Premi\u00e8re, vous pouvez am\u00e9liorer votre exp\u00e9rience utilisateur gr\u00e2ce \u00e0 des fonctionnalit\u00e9s comme le Mode Cin\u00e9ma ?",
|
||||
"MessageDidYouKnowCinemaMode2": "Le mode Cin\u00e9ma vous apporte une vraie exp\u00e9rience utilisateur de cin\u00e9ma, avec les bandes-annonces et les intros personnalis\u00e9es avant le film principal.",
|
||||
"HeaderPlayMyMedia": "Lire mon contenu",
|
||||
"HeaderDiscoverEmbyPremiere": "D\u00e9couvrez Emby Premiere",
|
||||
"OneChannel": "Une cha\u00eene",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.",
|
||||
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.",
|
||||
"MessageToValidateSupporter": "If you have an active Emby Premiere subscription, ensure you've setup Emby Premiere in your Emby Server Dashboard, which you can access by clicking Emby Premiere within the main menu.",
|
||||
"MessageUnlockAppWithPurchaseOrSupporter": "Otklju\u010daj ovu mogu\u0107nost s malom jednokratnom kupnjom ili s aktivnom pretplatom Emby Premijere.",
|
||||
"MessageUnlockAppWithSupporter": "Otklju\u010daj ovu mogu\u0107nost sa pretplatom Emby Premijere.",
|
||||
"MessageToValidateSupporter": "Ako imate aktivnu pretplatu Emby Premijere provjerite dali ste postavili Emby Premijeru u svojoj nadzornoj plo\u010di Emby Server-a kojoj mo\u017eete pristupiti klikom Emby Premijera u glavnom izborniku.",
|
||||
"ValueSpecialEpisodeName": "Specijal - {0}",
|
||||
"Share": "Dijeli",
|
||||
"Add": "Dodaj",
|
||||
@ -42,19 +42,19 @@
|
||||
"Saturday": "Subota",
|
||||
"Days": "Dani",
|
||||
"RecordSeries": "Snimi serije",
|
||||
"HeaderCinemaMode": "Cinema Mode",
|
||||
"HeaderCloudSync": "Cloud Sync",
|
||||
"HeaderOfflineDownloads": "Offline Media",
|
||||
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.",
|
||||
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.",
|
||||
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
|
||||
"HeaderCinemaMode": "Kino na\u010din",
|
||||
"HeaderCloudSync": "Sink. preko oblaka",
|
||||
"HeaderOfflineDownloads": "Izvanmre\u017eni mediji",
|
||||
"HeaderOfflineDownloadsDescription": "Preuzimanje medija na svojim ure\u0111ajima za jednostavnu upotrebu izvan mre\u017ee.",
|
||||
"CloudSyncFeatureDescription": "Sinkronizirajte svoje medije na oblaku za jednostavni backup, arhiviranje i konvertiranje.",
|
||||
"CoverArtFeatureDescription": "\"Cover Art\" stvara zabavne naslovnice i druge tretmane koji \u0107e vam pomo\u0107i personalizirati va\u0161e medijske slike.",
|
||||
"CoverArt": "Cover Art",
|
||||
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
|
||||
"HeaderFreeApps": "Free Emby Apps",
|
||||
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.",
|
||||
"CinemaModeFeatureDescription": "Kino na\u010din vam daje pravi do\u017eivljaj kina s kratkim filmovima i prilago\u0111enim isje\u010dcima prije odabrane zna\u010dajke.",
|
||||
"HeaderFreeApps": "Besplatne Emby aplikacije",
|
||||
"FreeAppsFeatureDescription": "U\u017eivajte u slobodnom pristupu Emby aplikacija za svoje ure\u0111aje.",
|
||||
"HeaderBecomeProjectSupporter": "Nabavite Emby Premijeru",
|
||||
"MessageActiveSubscriptionRequiredSeriesRecordings": "Aktivna pretplata Emby Premijere je potrebna kako bi se napravilo automatsko snimanje serija.",
|
||||
"LabelEmailAddress": "E-mail address:",
|
||||
"LabelEmailAddress": "E-mail adresa:",
|
||||
"PromoConvertRecordingsToStreamingFormat": "Automatski pretvoriti snimke na prijateljskom formatu strujanja s Emby Premijerom. Snimke \u0107e se pretvoriti u letu u MP4 ili MKV na temelju postavki Emby poslu\u017eitelja.",
|
||||
"FeatureRequiresEmbyPremiere": "Ova zna\u010dajka zahtijeva aktivnu pretplatu Emby Premijere.",
|
||||
"HeaderConvertYourRecordings": "Konvertiraj snimke",
|
||||
@ -236,7 +236,7 @@
|
||||
"PackageInstallCompleted": "{0} instaliranje zavr\u0161eno.",
|
||||
"PackageInstallFailed": "{0} instaliranje neuspjelo.",
|
||||
"PackageInstallCancelled": "{0} instaliranje otkazano.",
|
||||
"SeriesYearToPresent": "{0}-sada",
|
||||
"SeriesYearToPresent": "{0} - sada",
|
||||
"ValueOneSong": "1 pjesma",
|
||||
"ValueSongCount": "{0} pjesma",
|
||||
"ValueOneMovie": "1 film",
|
||||
@ -334,21 +334,25 @@
|
||||
"SortChannelsBy": "Slo\u017ei kanale po:",
|
||||
"RecentlyWatched": "Nedavno pogledano",
|
||||
"ChannelNumber": "Broj kanala",
|
||||
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.",
|
||||
"HeaderTryPlayback": "Try Playback",
|
||||
"HowDidYouPay": "How did you pay?",
|
||||
"IHaveEmbyPremiere": "I have Emby Premiere",
|
||||
"IPurchasedThisApp": "I purchased this app",
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"HeaderBenefitsEmbyPremiere": "Prednosti Emby premijere",
|
||||
"ThankYouForTryingEnjoyOneMinute": "Molimo Vas da u\u017eivate u jednoj minuti reprodukcije. Hvala \u0161to ste isprobali Emby.",
|
||||
"HeaderTryPlayback": "Isprobajte reprodukciju",
|
||||
"HowDidYouPay": "Kako ste platili?",
|
||||
"IHaveEmbyPremiere": "Imam Emby Premijeru",
|
||||
"IPurchasedThisApp": "Kupio sam ovu aplikaciju",
|
||||
"ButtonRestorePreviousPurchase": "Vrati kupovinu",
|
||||
"ButtonUnlockWithPurchase": "Otklju\u010daj s kupovinom",
|
||||
"ButtonUnlockPrice": "Otklju\u010daj {0}",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Reproduciraj jednu minutu",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Postavi omiljene kanale na po\u010detak",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderUnlockFeature": "Otklju\u010daj zna\u010dajke",
|
||||
"MessageDidYouKnowCinemaMode": "Jeste li znali da s Emby Premijerom mo\u017eete pobolj\u0161ati svoje iskustvo sa zna\u010dajkama kao \u0161to su na\u010din kina?",
|
||||
"MessageDidYouKnowCinemaMode2": "Kino na\u010din vam daje pravi do\u017eivljaj kina s kratkim filmovima i prilago\u0111enim isje\u010dcima prije odabrane zna\u010dajke.",
|
||||
"HeaderPlayMyMedia": "Reproduciraj moje medije",
|
||||
"HeaderDiscoverEmbyPremiere": "Otkrijte Emby Premijeru",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Added {0}"
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
"Add": "Hozz\u00e1ad",
|
||||
"ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}",
|
||||
"LiveTvGuideRequiresUnlock": "The Live TV Guide is currently limited to {0} channels. Click the unlock button to learn how to enjoy the full experience.",
|
||||
"AttributeNew": "New",
|
||||
"AttributeNew": "\u00daj",
|
||||
"Premiere": "Premiere",
|
||||
"Live": "Live",
|
||||
"Repeat": "Ism\u00e9tl\u00e9s",
|
||||
@ -15,7 +15,7 @@
|
||||
"ItemCount": "{0} items",
|
||||
"ReleaseYearValue": "Release year: {0}",
|
||||
"OriginalAirDateValue": "Original air date: {0}",
|
||||
"EndsAtValue": "Ends at {0}",
|
||||
"EndsAtValue": "V\u00e1rhat\u00f3 befejez\u00e9s {0}",
|
||||
"OptionSundayShort": "Sun",
|
||||
"OptionMondayShort": "Mon",
|
||||
"OptionTuesdayShort": "Tue",
|
||||
@ -32,7 +32,7 @@
|
||||
"SeriesCancelled": "Series cancelled.",
|
||||
"RecordingScheduled": "Recording scheduled.",
|
||||
"SeriesRecordingScheduled": "Series recording scheduled.",
|
||||
"HeaderNewRecording": "New Recording",
|
||||
"HeaderNewRecording": "\u00daj Felv\u00e9tel",
|
||||
"Sunday": "Vas\u00e1rnap",
|
||||
"Monday": "H\u00e9tf\u0151",
|
||||
"Tuesday": "Kedd",
|
||||
@ -117,13 +117,13 @@
|
||||
"Shuffle": "Kever\u00e9s",
|
||||
"Identify": "Azonos\u00edt\u00e1s",
|
||||
"EditImages": "K\u00e9pek szerkeszt\u00e9se",
|
||||
"EditInfo": "Edit info",
|
||||
"EditInfo": "Adatok szerkeszt\u00e9se",
|
||||
"Sync": "Sync",
|
||||
"InstantMix": "Instant mix",
|
||||
"ViewAlbum": "View album",
|
||||
"ViewArtist": "View artist",
|
||||
"QueueAllFromHere": "Queue all from here",
|
||||
"PlayAllFromHere": "Play all from here",
|
||||
"PlayAllFromHere": "\u00d6sszes vet\u00edt\u00e9se innen",
|
||||
"PlayFromBeginning": "Play from beginning",
|
||||
"ResumeAt": "Resume from {0}",
|
||||
"RemoveFromPlaylist": "Remove from playlist",
|
||||
@ -182,7 +182,7 @@
|
||||
"LabelAirsBeforeSeason": "Airs before season:",
|
||||
"LabelAirsAfterSeason": "Airs after season:",
|
||||
"LabelAirsBeforeEpisode": "Airs before episode:",
|
||||
"HeaderExternalIds": "External Id's:",
|
||||
"HeaderExternalIds": "External Ids:",
|
||||
"HeaderDisplaySettings": "Display Settings",
|
||||
"LabelTreatImageAs": "Treat image as:",
|
||||
"LabelDisplayOrder": "Display order:",
|
||||
@ -286,7 +286,7 @@
|
||||
"HeaderEditImages": "Edit Images",
|
||||
"Settings": "Be\u00e1ll\u00edt\u00e1sok",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
"NewEpisodes": "New episodes",
|
||||
"NewEpisodes": "\u00daj epiz\u00f3dok",
|
||||
"HDPrograms": "HD programs",
|
||||
"LiveBroadcasts": "Live broadcasts",
|
||||
"Premieres": "Premieres",
|
||||
@ -311,7 +311,7 @@
|
||||
"LabelAirtime": "Airtime:",
|
||||
"AllChannels": "All channels",
|
||||
"LabelRecord": "Record:",
|
||||
"NewEpisodesOnly": "New episodes only",
|
||||
"NewEpisodesOnly": "Csak \u00faj epiz\u00f3dok",
|
||||
"AllEpisodes": "All episodes",
|
||||
"LabelStartWhenPossible": "Start when possible:",
|
||||
"LabelStopWhenPossible": "Stop when possible:",
|
||||
@ -343,12 +343,16 @@
|
||||
"ButtonRestorePreviousPurchase": "Restore Purchase",
|
||||
"ButtonUnlockWithPurchase": "Unlock with Purchase",
|
||||
"ButtonUnlockPrice": "Unlock {0}",
|
||||
"ButtonAlreadyPaid": "Already Paid?",
|
||||
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
|
||||
"HeaderAlreadyPaid": "Already Paid?",
|
||||
"ButtonPlayOneMinute": "Play One Minute",
|
||||
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
|
||||
"HeaderUnlockFeature": "Unlock Feature",
|
||||
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
|
||||
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
|
||||
"HeaderPlayMyMedia": "Play my Media",
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
|
||||
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
|
||||
"OneChannel": "One channel",
|
||||
"ConfirmRemoveDownload": "Remove download?",
|
||||
"AddedOnValue": "Hozz\u00e1adva {0}"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user