1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge pull request #2350 from MediaBrowser/beta

Beta
This commit is contained in:
Luke 2016-12-18 00:44:33 -05:00 committed by GitHub
commit e8446c0dfe
408 changed files with 19581 additions and 20065 deletions

View 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>

View file

@ -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>

View file

@ -16,12 +16,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.1.91", "version": "1.1.105",
"_release": "1.1.91", "_release": "1.1.105",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.1.91", "tag": "1.1.105",
"commit": "f94b80f14bce6922acf1dbd749a60ad54e4abfd8" "commit": "d46515271d43d1b0f7dd19bb1834cfd457fb3326"
}, },
"_source": "https://github.com/MediaBrowser/Emby.ApiClient.Javascript.git", "_source": "https://github.com/MediaBrowser/Emby.ApiClient.Javascript.git",
"_target": "^1.1.51", "_target": "^1.1.51",

View file

@ -22,6 +22,27 @@
var self = this; var self = this;
var webSocket; var webSocket;
var serverInfo = {}; 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. * Gets the server address.
@ -38,9 +59,14 @@
serverAddress = val; serverAddress = val;
lastDetectedBitrate = 0;
lastDetectedBitrateTime = 0;
if (changed) { if (changed) {
events.trigger(this, 'serveraddresschanged'); events.trigger(this, 'serveraddresschanged');
} }
redetectBitrate();
} }
return serverAddress; return serverAddress;
@ -128,6 +154,7 @@
serverInfo.AccessToken = accessKey; serverInfo.AccessToken = accessKey;
serverInfo.UserId = userId; serverInfo.UserId = userId;
redetectBitrate();
}; };
self.encodeName = function (name) { self.encodeName = function (name) {
@ -239,7 +266,7 @@
resolve(response); resolve(response);
}, function (error) { }, function (error) {
clearTimeout(timeout); clearTimeout(timeout);
reject(); reject(error);
}); });
}); });
} }
@ -421,11 +448,14 @@
}, function (error) { }, function (error) {
console.log("Request failed to " + request.url); if (error) {
console.log("Request failed to " + request.url + ' ' + error.toString());
// http://api.jquery.com/jQuery.ajax/ } else {
if (enableReconnection) { console.log("Request timed out to " + request.url + ' ' + error.toString());
}
// http://api.jquery.com/jQuery.ajax/
if (!error && enableReconnection) {
console.log("Attempting reconnection"); console.log("Attempting reconnection");
var previousServerAddress = self.serverAddress(); 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 if (!bitrate) {
return self.getDownloadSpeed(1000000).then(function (bitrate) {
if (bitrate < 1000000) { if (lastDetectedBitrate) {
return Math.round(bitrate * 0.8); return lastDetectedBitrate;
} 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);
});
} }
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 () { self.logout = function () {
stopBitrateDetection();
self.closeWebSocket(); self.closeWebSocket();
var done = function () { var done = function () {
@ -2561,6 +2636,8 @@
self.onAuthenticated(self, result); self.onAuthenticated(self, result);
} }
redetectBitrate();
resolve(result); resolve(result);
}, reject); }, reject);
@ -3311,6 +3388,8 @@
throw new Error("null options"); throw new Error("null options");
} }
stopBitrateDetection();
var url = self.getUrl("Sessions/Playing"); var url = self.getUrl("Sessions/Playing");
return self.ajax({ return self.ajax({
@ -3439,6 +3518,8 @@
throw new Error("null options"); throw new Error("null options");
} }
redetectBitrate();
var url = self.getUrl("Sessions/Playing/Stopped"); var url = self.getUrl("Sessions/Playing/Stopped");
return self.ajax({ return self.ajax({

View file

@ -6,7 +6,10 @@
var localData; var localData;
function updateCache() { 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) { myStore.setItem = function (name, value) {
@ -38,10 +41,13 @@
try { try {
caches.open('embydata').then(function (result) { if (self.caches) {
cache = result;
localData = {}; caches.open('embydata').then(function (result) {
}); cache = result;
localData = {};
});
}
} catch (err) { } catch (err) {
console.log('Error opening cache: ' + err); console.log('Error opening cache: ' + err);

View file

@ -216,7 +216,7 @@
return connectUser; return connectUser;
}; };
var minServerVersion = '3.0.5994'; var minServerVersion = '3.0.7200';
self.minServerVersion = function (val) { self.minServerVersion = function (val) {
if (val) { if (val) {
@ -447,6 +447,7 @@
if (options.reportCapabilities !== false) { if (options.reportCapabilities !== false) {
apiClient.reportCapabilities(capabilities); apiClient.reportCapabilities(capabilities);
} }
apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
if (options.enableWebSocket !== false) { if (options.enableWebSocket !== false) {
console.log('calling apiClient.ensureWebSocket'); console.log('calling apiClient.ensureWebSocket');
@ -1509,7 +1510,7 @@
var updateDevicePromise; var updateDevicePromise;
// Cache for 3 days // 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'); console.log('getRegistrationInfo has cached info');

View 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
};
});

View 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
};
});

View 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
};
});

View 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';
}
};
});

View file

@ -1,471 +1,488 @@
define(['localassetmanager'], function (LocalAssetManager) { define(['localassetmanager'], function (localassetmanager) {
'use strict'; '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 () { return function () {
var self = this; var self = this;
self.sync = function (apiClient, serverInfo, options) { self.sync = function (apiClient, serverInfo, options) {
return reportOfflineActions(apiClient, serverInfo).then(function () { console.log("[mediasync]************************************* Start sync");
// Do the first data sync return processDownloadStatus(apiClient, serverInfo, options).then(function () {
return syncData(apiClient, serverInfo, false).then(function () {
return reportOfflineActions(apiClient, serverInfo).then(function () {
//// Do the first data sync
//return syncData(apiClient, serverInfo, false).then(function () {
// Download new content // Download new content
return getNewMedia(apiClient, serverInfo, options).then(function () { return getNewMedia(apiClient, serverInfo, options).then(function () {
// Do the second data sync // 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();
//}
//}
}); });

View file

@ -16,7 +16,8 @@
var connectionOptions = { var connectionOptions = {
updateDateLastAccessed: false, updateDateLastAccessed: false,
enableWebSocket: false, enableWebSocket: false,
reportCapabilities: false reportCapabilities: false,
enableAutomaticBitrateDetection: false
}; };
return connectionManager.connectToServer(server, connectionOptions).then(function (result) { return connectionManager.connectToServer(server, connectionOptions).then(function (result) {
@ -37,7 +38,7 @@
function performSync(server, options) { function performSync(server, options) {
console.log("Creating ContentUploader to server: " + server.Id); console.log("ServerSync.performSync to server: " + server.Id);
options = options || {}; options = options || {};
@ -47,34 +48,27 @@
uploadPhotos = false; uploadPhotos = false;
} }
if (!uploadPhotos) { var pr = syncOfflineUsers(server, options);
return 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); return syncMedia(server, options);
}, function () {
console.log("ContentUploaded failed to server: " + server.Id);
syncOfflineUsers(server, options).then(resolve, reject);
});
});
}); });
} }
function syncOfflineUsers(server, options) { function syncOfflineUsers(server, options) {
if (options.syncOfflineUsers === false) { if (options.syncOfflineUsers === false) {
return syncMedia(server, options); return Promise.resolve();
} }
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
@ -83,13 +77,19 @@
var apiClient = connectionManager.getApiClient(server.Id); 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);
}); });
}); });
} }

View 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
};
});

View 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
};
});

View 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
};
});

View file

@ -14,12 +14,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.4.321", "version": "1.4.390",
"_release": "1.4.321", "_release": "1.4.390",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.4.321", "tag": "1.4.390",
"commit": "fb270e69c8391f62e762ee03d77a7b8a495c5a6f" "commit": "075f424628a8208d15eca0ed024fe4d8f6bf43fa"
}, },
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.1", "_target": "^1.2.1",

View file

@ -140,7 +140,7 @@
var html = ''; var html = '';
var scrollType = layoutManager.desktop ? 'smoothScrollY' : 'hiddenScrollY'; 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 // Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
if (options.items.length > 20) { if (options.items.length > 20) {
@ -193,7 +193,7 @@
html += '<div class="actionSheetScroller ' + scrollType + '" style="' + style + '">'; 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) { if (options.menuItemClass) {
menuItemClass += ' ' + options.menuItemClass; menuItemClass += ' ' + options.menuItemClass;

View file

@ -40,7 +40,7 @@
backdropImage.style.backgroundImage = "url('" + url + "')"; backdropImage.style.backgroundImage = "url('" + url + "')";
backdropImage.setAttribute('data-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); parent.appendChild(backdropImage);
if (!enableAnimation(backdropImage)) { if (!enableAnimation(backdropImage)) {
@ -52,7 +52,7 @@
} }
var onAnimationComplete = function () { var onAnimationComplete = function () {
dom.removeEventListener(backdropImage, 'animationend', onAnimationComplete, { dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true once: true
}); });
if (backdropImage === currentAnimatingElement) { if (backdropImage === currentAnimatingElement) {
@ -63,7 +63,7 @@
} }
}; };
dom.addEventListener(backdropImage, 'animationend', onAnimationComplete, { dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true once: true
}); });
@ -75,7 +75,7 @@
function cancelAnimation() { function cancelAnimation() {
var elem = currentAnimatingElement; var elem = currentAnimatingElement;
if (elem) { if (elem) {
elem.style.animation = ''; elem.classList.remove('backdropImageFadeIn');
currentAnimatingElement = null; currentAnimatingElement = null;
} }
} }
@ -176,7 +176,24 @@
currentLoadingBackdrop = instance; 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); var apiClient = connectionManager.getApiClient(item.ServerId);
@ -184,12 +201,12 @@
return item.BackdropImageTags.map(function (imgTag, index) { return item.BackdropImageTags.map(function (imgTag, index) {
return apiClient.getScaledImageUrl(item.Id, { return apiClient.getScaledImageUrl(item.Id, Object.assign(imageOptions, {
type: "Backdrop", type: "Backdrop",
tag: imgTag, tag: imgTag,
maxWidth: Math.min(dom.getWindowSize().innerWidth, 1920), maxWidth: getBackdropMaxWidth(),
index: index index: index
}); }));
}); });
} }
@ -197,19 +214,19 @@
return item.ParentBackdropImageTags.map(function (imgTag, index) { return item.ParentBackdropImageTags.map(function (imgTag, index) {
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, { return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
type: "Backdrop", type: "Backdrop",
tag: imgTag, tag: imgTag,
maxWidth: Math.min(dom.getWindowSize().innerWidth, 1920), maxWidth: getBackdropMaxWidth(),
index: index index: index
}); }));
}); });
} }
return []; return [];
} }
function getImageUrls(items) { function getImageUrls(items, imageOptions) {
var list = []; var list = [];
@ -219,7 +236,7 @@
for (var i = 0, length = items.length; i < length; i++) { for (var i = 0, length = items.length; i < length; i++) {
var itemImages = getItemImageUrls(items[i]); var itemImages = getItemImageUrls(items[i], imageOptions);
itemImages.forEach(onImg); itemImages.forEach(onImg);
} }
@ -252,21 +269,20 @@
var rotationInterval; var rotationInterval;
var currentRotatingImages = []; var currentRotatingImages = [];
var currentRotationIndex = -1; 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) { if (images.length) {
startRotation(images, imageSetId); startRotation(images, enableImageRotation);
} else { } else {
clearBackdrop(); clearBackdrop();
} }
} }
function startRotation(images) { function startRotation(images, enableImageRotation) {
if (arraysEqual(images, currentRotatingImages)) { if (arraysEqual(images, currentRotatingImages)) {
return; return;
@ -277,7 +293,7 @@
currentRotatingImages = images; currentRotatingImages = images;
currentRotationIndex = -1; currentRotationIndex = -1;
if (images.length > 1 && enableRotation()) { if (images.length > 1 && enableImageRotation !== false && enableRotation()) {
rotationInterval = setInterval(onRotationInterval, 20000); rotationInterval = setInterval(onRotationInterval, 20000);
} }
onRotationInterval(); onRotationInterval();
@ -308,10 +324,12 @@
currentRotationIndex = -1; currentRotationIndex = -1;
} }
function setBackdrop(url) { function setBackdrop(url, imageOptions) {
if (typeof url !== 'string') { if (url) {
url = getImageUrls([url])[0]; if (typeof url !== 'string') {
url = getImageUrls([url], imageOptions)[0];
}
} }
if (url) { if (url) {

View file

@ -15,6 +15,10 @@
contain: layout style; contain: layout style;
} }
.backdropImageFadeIn {
animation: backdrop-fadein 800ms ease-in normal both;
}
@keyframes backdrop-fadein { @keyframes backdrop-fadein {
from { from {
opacity: 0; opacity: 0;
@ -23,4 +27,4 @@
to { to {
opacity: 1; opacity: 1;
} }
} }

View file

@ -55,6 +55,11 @@
} }
function isStyleSupported(prop, value) { function isStyleSupported(prop, value) {
if (typeof window === 'undefined') {
return false;
}
// If no value is supplied, use "inherit" // If no value is supplied, use "inherit"
value = arguments.length === 2 ? value : 'inherit'; value = arguments.length === 2 ? value : 'inherit';
// Try the native standard method first // Try the native standard method first
@ -116,6 +121,50 @@
return false; 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) { var uaMatch = function (ua) {
ua = ua.toLowerCase(); ua = ua.toLowerCase();
@ -176,7 +225,7 @@
}; };
}; };
var userAgent = window.navigator.userAgent; var userAgent = navigator.userAgent;
var matched = uaMatch(userAgent); var matched = uaMatch(userAgent);
var browser = {}; var browser = {};
@ -204,7 +253,7 @@
} }
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1; 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.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || userAgent.toLowerCase().indexOf('smarthub') !== -1;
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1; browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
browser.edgeUwp = browser.edge && userAgent.toLowerCase().indexOf('msapphost') !== -1; browser.edgeUwp = browser.edge && userAgent.toLowerCase().indexOf('msapphost') !== -1;
@ -220,11 +269,17 @@
browser.slow = true; browser.slow = true;
} }
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { if (typeof document !== 'undefined') {
browser.touch = true; if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
browser.touch = true;
}
} }
browser.keyboard = hasKeyboard(browser); 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; return browser;
}); });

View file

@ -53,7 +53,7 @@ button {
position: relative; position: relative;
} }
.cardPadder-backdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop { .cardPadder-backdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop, .cardPadder-overflowSmallBackdrop {
padding-bottom: 56.25%; padding-bottom: 56.25%;
} }
@ -107,7 +107,7 @@ button {
.btnCardOptions { .btnCardOptions {
position: absolute; position: absolute;
bottom: 0; bottom: .25em;
right: 0; right: 0;
margin: 0 !important; margin: 0 !important;
z-index: 1; z-index: 1;
@ -133,7 +133,6 @@ button {
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center;
display: -ms-flex;
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;
@ -403,12 +402,16 @@ button {
max-width: 400px; max-width: 400px;
} }
.overflowSmallBackdropCard-scalable {
width: 60%;
}
.overflowSquareCard-scalable { .overflowSquareCard-scalable {
width: 42%; width: 42%;
max-width: 200px; max-width: 200px;
} }
@media all and (min-width: 420px) { @media all and (min-width: 400px) {
.backdropCard-scalable { .backdropCard-scalable {
width: 50%; width: 50%;
@ -439,6 +442,10 @@ button {
.overflowSquareCard-scalable { .overflowSquareCard-scalable {
width: 30%; width: 30%;
} }
.overflowSmallBackdropCard-scalable {
width: 40%
}
} }
@media all and (min-width: 640px) { @media all and (min-width: 640px) {
@ -450,6 +457,10 @@ button {
.overflowBackdropCard-scalable { .overflowBackdropCard-scalable {
width: 56%; width: 56%;
} }
.overflowSmallBackdropCard-scalable {
width: 40%
}
} }
@media all and (min-width: 700px) { @media all and (min-width: 700px) {
@ -462,6 +473,10 @@ button {
.backdropCard-scalable { .backdropCard-scalable {
width: 33.333333333333333333333333333333%; width: 33.333333333333333333333333333333%;
} }
.overflowSmallBackdropCard-scalable {
width: 30%
}
} }
@media all and (min-width: 800px) { @media all and (min-width: 800px) {
@ -502,6 +517,10 @@ button {
width: 40%; width: 40%;
} }
.overflowSmallBackdropCard-scalable {
width: 24%
}
.overflowSquareCard-scalable { .overflowSquareCard-scalable {
width: 22%; width: 22%;
} }
@ -528,6 +547,10 @@ button {
.smallBackdropCard-scalable { .smallBackdropCard-scalable {
width: 16.666666666666666666666666666667%; width: 16.666666666666666666666666666667%;
} }
.overflowSmallBackdropCard-scalable {
width: 18%
}
} }

View file

@ -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'], 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, mediaInfo, focusManager, indicators, globalize, layoutManager, appHost, dom) { function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser) {
'use strict'; 'use strict';
var devicePixelRatio = window.devicePixelRatio || 1; var devicePixelRatio = window.devicePixelRatio || 1;
@ -144,6 +144,20 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
return 100 / 64; return 100 / 64;
} }
return 100 / 72; 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: default:
return 4; return 4;
} }
@ -689,7 +703,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
return 'defaultCardColor' + getDefaultColorIndex(str); return 'defaultCardColor' + getDefaultColorIndex(str);
} }
function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin) { function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) {
var html = ''; var html = '';
@ -714,10 +728,17 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
html += text; html += text;
html += "</div>"; html += "</div>";
valid++; valid++;
if (maxLines && valid >= maxLines) {
break;
}
} }
} }
if (forceLines) { if (forceLines) {
length = Math.min(lines.length, maxLines || lines.length);
while (valid < length) { while (valid < length) {
html += "<div class='" + cssClass + "'>&nbsp;</div>"; html += "<div class='" + cssClass + "'>&nbsp;</div>";
valid++; valid++;
@ -792,7 +813,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
if (showMediaTitle) { 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); lines.push(name);
} }
@ -964,8 +987,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
if (item.RecordAnyChannel) { if (item.RecordAnyChannel) {
lines.push(globalize.translate('sharedcomponents#AllChannels')); lines.push(globalize.translate('sharedcomponents#AllChannels'));
} }
else if (item.ChannelId) { else {
lines.push(item.ChannelName || ''); lines.push(item.ChannelName || globalize.translate('sharedcomponents#OneChannel'));
} }
} }
@ -974,7 +997,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
lines.push('as ' + item.Role); lines.push('as ' + item.Role);
} }
else if (item.Type) { else if (item.Type) {
lines.push(globalize.translate('core#' + item.Type)); lines.push(globalize.translate('sharedcomponents#' + item.Type));
} else { } else {
lines.push(''); lines.push('');
} }
@ -985,7 +1008,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
lines = []; 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) { if (progressHtml) {
html += progressHtml; html += progressHtml;
@ -1041,10 +1064,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
minutes = minutes || 1; minutes = minutes || 1;
childText += globalize.translate('ValueMinutes', Math.round(minutes)); childText += globalize.translate('sharedcomponents#ValueMinutes', Math.round(minutes));
} else { } else {
childText += globalize.translate('ValueMinutes', 0); childText += globalize.translate('sharedcomponents#ValueMinutes', 0);
} }
counts.push(childText); 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') { 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) { if (options.overlayMoreButton) {
@ -1268,7 +1291,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
cardContentClose = '</button>'; 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 + '">'; cardImageContainerOpen = '<div class="' + cardImageContainerClass + '">';
var imgClass = 'cardImage cardImage-img lazy'; var imgClass = 'cardImage cardImage-img lazy';
@ -1279,10 +1307,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
imgClass += ' coveredImage-img'; 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 { } 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'; var cardScalableClass = options.cardLayout ? 'cardScalable visualCardBox-cardScalable' : 'cardScalable';

View file

@ -42,9 +42,6 @@
Name: dlg.querySelector('#txtNewCollectionName').value, Name: dlg.querySelector('#txtNewCollectionName').value,
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked, IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
Ids: dlg.querySelector('.fldSelectedItemIds').value || '' Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
//ParentId: getParameterByName('parentId') || LibraryMenu.getTopParentId()
}); });
apiClient.ajax({ apiClient.ajax({

View file

@ -110,30 +110,70 @@
return locale; 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) { function toLocaleString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale(); var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ? if (currentLocale && toLocaleTimeStringSupportsLocales) {
date.toLocaleString(currentLocale, options || {}) : return date.toLocaleString(currentLocale, options);
date.toLocaleString(); }
return date.toLocaleString();
} }
function toLocaleDateString(date, options) { function toLocaleDateString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale(); var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ? if (currentLocale && toLocaleTimeStringSupportsLocales) {
date.toLocaleDateString(currentLocale, options || {}) : return date.toLocaleDateString(currentLocale, options);
date.toLocaleDateString(); }
// 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) { function toLocaleTimeString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale(); var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ? if (currentLocale && toLocaleTimeStringSupportsLocales) {
date.toLocaleTimeString(currentLocale, options || {}).toLowerCase() : return date.toLocaleTimeString(currentLocale, options);
date.toLocaleTimeString().toLowerCase(); }
return date.toLocaleTimeString();
} }
function getDisplayTime(date) { function getDisplayTime(date) {

View 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
};
});

View file

@ -5,20 +5,12 @@
function enableAnimation() { function enableAnimation() {
if (browser.animate) { // too slow
return true; if (browser.tv) {
}
if (browser.edge) {
return true;
}
// An indication of an older browser
if (browser.noFlex) {
return false; return false;
} }
return true; return browser.supportsCssAnimation();
} }
function removeCenterFocus(dlg) { function removeCenterFocus(dlg) {
@ -246,12 +238,12 @@
if (enableAnimation()) { if (enableAnimation()) {
var onFinish = function () { var onFinish = function () {
dom.removeEventListener(dlg, 'animationend', onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
onAnimationFinish(); onAnimationFinish();
}; };
dom.addEventListener(dlg, 'animationend', onFinish, { dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
return; return;
@ -265,6 +257,7 @@
if (enableAnimation()) { if (enableAnimation()) {
var animated = true; var animated = true;
switch (dlg.animationConfig.exit.name) { switch (dlg.animationConfig.exit.name) {
case 'fadeout': case 'fadeout':
@ -281,12 +274,12 @@
break; break;
} }
var onFinish = function () { var onFinish = function () {
dom.removeEventListener(dlg, 'animationend', onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
onAnimationFinish(); onAnimationFinish();
}; };
dom.addEventListener(dlg, 'animationend', onFinish, { dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
@ -436,6 +429,7 @@
} }
if (enableAnimation()) { if (enableAnimation()) {
switch (dlg.animationConfig.entry.name) { switch (dlg.animationConfig.entry.name) {
case 'fadein': case 'fadein':

View file

@ -94,12 +94,65 @@ define([], function () {
return windowSize; 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 { return {
parentWithAttribute: parentWithAttribute, parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass, parentWithClass: parentWithClass,
parentWithTag: parentWithTag, parentWithTag: parentWithTag,
addEventListener: addEventListenerWithOptions, addEventListener: addEventListenerWithOptions,
removeEventListener: removeEventListenerWithOptions, removeEventListener: removeEventListenerWithOptions,
getWindowSize: getWindowSize getWindowSize: getWindowSize,
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent
}; };
}); });

View file

@ -15,7 +15,7 @@
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
z-index: 0; z-index: 0;
padding: 0.7em 0.57em; padding: 1em .7em;
font-weight: normal; font-weight: normal;
vertical-align: middle; vertical-align: middle;
border: 0; border: 0;
@ -40,6 +40,18 @@
text-transform: uppercase; 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 { .emby-button > i {
/* For non-fab buttons that have icons */ /* For non-fab buttons that have icons */
font-size: 1.36em; font-size: 1.36em;
@ -50,7 +62,7 @@
.fab { .fab {
display: inline-flex; display: inline-flex;
border-radius: 50%; border-radius: 50%;
background-color: #444; background-color: rgba(170,170,190, .4);
padding: .6em; padding: .6em;
box-sizing: border-box; box-sizing: border-box;
align-items: center; align-items: center;
@ -220,3 +232,14 @@
position: relative; position: relative;
z-index: 1; 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;
}

View file

@ -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'; 'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
@ -26,7 +26,7 @@
btn.appendChild(div); btn.appendChild(div);
} }
div.addEventListener("animationend", function () { div.addEventListener(dom.whichAnimationEvent(), function () {
div.parentNode.removeChild(div); div.parentNode.removeChild(div);
}, false); }, false);
} }
@ -73,10 +73,15 @@
this.classList.add('emby-button'); 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'); this.classList.add('emby-button-noflex');
} }
if (layoutManager.tv) {
this.classList.add('emby-button-focusscale');
}
if (enableAnimation()) { if (enableAnimation()) {
dom.addEventListener(this, 'keydown', onKeyDown, { dom.addEventListener(this, 'keydown', onKeyDown, {
passive: true passive: true

View file

@ -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'; 'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
@ -29,7 +29,7 @@
btn.appendChild(div); btn.appendChild(div);
div.addEventListener("animationend", function () { div.addEventListener(dom.whichAnimationEvent(), function () {
div.parentNode.removeChild(div); div.parentNode.removeChild(div);
}, false); }, false);
} }
@ -61,6 +61,10 @@
this.classList.add('paper-icon-button-light'); this.classList.add('paper-icon-button-light');
if (layoutManager.tv) {
this.classList.add('icon-button-focusscale');
}
if (enableAnimation()) { if (enableAnimation()) {
dom.addEventListener(this, 'keydown', onKeyDown, { dom.addEventListener(this, 'keydown', onKeyDown, {
passive: true passive: true

View file

@ -2,7 +2,7 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
vertical-align: middle; vertical-align: middle;
display: inline-block; display: inline-flex;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -18,18 +18,7 @@
.checkboxContainer { .checkboxContainer {
margin-bottom: 1.8em; margin-bottom: 1.8em;
display: block;
}
@supports (display: flex) {
.mdl-checkbox {
display: inline-flex;
}
.checkboxContainer {
display: flex; display: flex;
}
} }
.checkboxContainer-withDescription { .checkboxContainer-withDescription {

View file

@ -119,6 +119,8 @@
var serverId = el.getAttribute('data-serverid'); var serverId = el.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId); var apiClient = connectionManager.getApiClient(serverId);
newIndex = Math.max(0, newIndex - 1);
apiClient.ajax({ apiClient.ajax({
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex), url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),

View file

@ -2,7 +2,6 @@
display: block; display: block;
margin: 0; margin: 0;
margin-bottom: 0 !important; margin-bottom: 0 !important;
background: none;
border: 1px solid #383838; border: 1px solid #383838;
border-width: 0 0 1px 0; border-width: 0 0 1px 0;
/* Prefixed box-sizing rules necessary for older browsers */ /* Prefixed box-sizing rules necessary for older browsers */
@ -15,17 +14,21 @@
/* General select styles: change as needed */ /* General select styles: change as needed */
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
color: inherit;
padding: .35em .8em .3em 0; padding: .35em .8em .3em 0;
cursor: pointer; cursor: pointer;
outline: none !important; outline: none !important;
width: 100%; width: 100%;
}
.emby-select-withoptioncolor {
color: inherit;
background: none;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
appearance: none; appearance: none;
} }
.emby-select option { .emby-select-withoptioncolor > option {
color: initial; color: initial;
} }

View file

@ -118,6 +118,10 @@
inputId++; inputId++;
} }
if (!browser.firefox) {
this.classList.add('emby-select-withoptioncolor');
}
this.addEventListener('mousedown', onMouseDown); this.addEventListener('mousedown', onMouseDown);
this.addEventListener('keydown', onKeyDown); this.addEventListener('keydown', onKeyDown);

View file

@ -16,7 +16,7 @@ _:-ms-input-placeholder, :root .mdl-slider {
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
outline: 0; outline: 0;
padding: 0; padding: 1.5em 0;
color: #52B54B; color: #52B54B;
-webkit-align-self: center; -webkit-align-self: center;
-ms-flex-item-align: center; -ms-flex-item-align: center;
@ -24,6 +24,9 @@ _:-ms-input-placeholder, :root .mdl-slider {
z-index: 1; z-index: 1;
cursor: pointer; cursor: pointer;
margin: 0; margin: 0;
/* Disable webkit tap highlighting */
-webkit-tap-highlight-color: rgba(0,0,0,0);
display: block;
/**************************** Tracks ****************************/ /**************************** Tracks ****************************/
/**************************** Thumbs ****************************/ /**************************** Thumbs ****************************/
/**************************** 0-value ****************************/ /**************************** 0-value ****************************/
@ -77,83 +80,85 @@ _:-ms-input-placeholder, :root .mdl-slider {
border-radius: 50%; border-radius: 50%;
background: #52B54B; background: #52B54B;
border: none; 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);
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 { .slider-no-webkit-thumb::-webkit-slider-thumb {
-moz-appearance: none; opacity: 0 !important;
width: 1em; }
height: 1em;
box-sizing: border-box;
border-radius: 50%;
background-image: none;
background: #52B54B;
border: none;
}
.mdl-slider:active::-webkit-slider-thumb { .mdl-slider::-moz-range-thumb {
background-image: none; -moz-appearance: none;
background: #52B54B; width: 1em;
-webkit-transform: scale(1.5); height: 1em;
transform: scale(1.5); box-sizing: border-box;
} border-radius: 50%;
background-image: none;
background: #52B54B;
border: none;
}
.mdl-slider:active::-moz-range-thumb { .mdl-slider:active::-webkit-slider-thumb {
background-image: none; background-image: none;
background: #52B54B; background: #52B54B;
transform: scale(1.5); -webkit-transform: scale(1.5);
} transform: scale(1.5);
}
.mdl-slider:focus::-webkit-slider-thumb { .mdl-slider:active::-moz-range-thumb {
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26); background-image: none;
} background: #52B54B;
transform: scale(1.5);
}
.mdl-slider:focus::-moz-range-thumb { .mdl-slider:focus::-webkit-slider-thumb {
box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26); box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
} }
.mdl-slider::-ms-thumb { .mdl-slider:focus::-moz-range-thumb {
width: 16px; box-shadow: 0 0 0 10px rgba(82, 181, 75, 0.26);
height: 16px; }
border: none;
border-radius: 50%;
background: #52B54B;
}
.mdl-slider[disabled]::-ms-thumb { .mdl-slider::-ms-thumb {
background: gray; 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 { .mdl-slider[disabled]::-ms-thumb {
-webkit-transform: scale(0.667); background: gray;
transform: scale(0.667); }
background: rgba(0,0,0, 0.26);
}
.mdl-slider:disabled:focus::-moz-range-thumb, .mdl-slider:disabled:active::-moz-range-thumb, .mdl-slider:disabled::-moz-range-thumb { .mdl-slider:disabled:focus::-webkit-slider-thumb, .mdl-slider:disabled:active::-webkit-slider-thumb, .mdl-slider:disabled::-webkit-slider-thumb {
transform: scale(0.667); -webkit-transform: scale(0.667);
background: rgba(0,0,0, 0.26); transform: scale(0.667);
} background: rgba(0,0,0, 0.26);
}
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-lower { .mdl-slider:disabled:focus::-moz-range-thumb, .mdl-slider:disabled:active::-moz-range-thumb, .mdl-slider:disabled::-moz-range-thumb {
background-color: #444; transform: scale(0.667);
left: -6px; background: rgba(0,0,0, 0.26);
} }
.mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-upper { .mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-lower {
left: 6px; background-color: #444;
} left: -6px;
}
.mdl-slider:disabled::-ms-fill-lower { .mdl-slider:disabled + .mdl-slider__background-flex > .mdl-slider__background-upper {
margin-right: 6px; left: 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 { .mdl-slider:disabled::-ms-fill-lower {
margin-left: 6px; 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 { .mdl-slider__ie-container {
height: 18px; height: 18px;
@ -224,3 +229,7 @@ _:-ms-input-placeholder, :root .mdl-slider {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.sliderBubbleText {
margin: 0;
}

View file

@ -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'; 'use strict';
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype); var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
@ -23,20 +23,27 @@
if (backgroundLower) { if (backgroundLower) {
var fraction = (value - range.min) / (range.max - range.min); 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; backgroundLower.style.flex = fraction;
backgroundUpper.style.flex = 1 - fraction; backgroundUpper.style.flex = 1 - fraction;
} }
}); });
} }
function updateBubble(range, value, bubble) { function updateBubble(range, value, bubble, bubbleText) {
bubble.style.left = (value - 1) + '%'; bubble.style.left = (value - 1) + '%';
if (range.getBubbleText) { if (range.getBubbleText) {
value = range.getBubbleText(value); value = range.getBubbleText(value);
} }
bubble.innerHTML = value; bubbleText.innerHTML = value;
} }
EmbySliderPrototype.attachedCallback = function () { EmbySliderPrototype.attachedCallback = function () {
@ -50,6 +57,10 @@
this.classList.add('mdl-slider'); this.classList.add('mdl-slider');
this.classList.add('mdl-js-slider'); this.classList.add('mdl-js-slider');
if (browser.noFlex) {
this.classList.add('slider-no-webkit-thumb');
}
var containerElement = this.parentNode; var containerElement = this.parentNode;
containerElement.classList.add('mdl-slider__container'); 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="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); containerElement.insertAdjacentHTML('beforeend', htmlToInsert);
var backgroundLower = containerElement.querySelector('.mdl-slider__background-lower'); var backgroundLower = containerElement.querySelector('.mdl-slider__background-lower');
var backgroundUpper = containerElement.querySelector('.mdl-slider__background-upper'); var backgroundUpper = containerElement.querySelector('.mdl-slider__background-upper');
var sliderBubble = containerElement.querySelector('.sliderBubble'); var sliderBubble = containerElement.querySelector('.sliderBubble');
var sliderBubbleText = containerElement.querySelector('.sliderBubbleText');
var hasHideClass = sliderBubble.classList.contains('hide'); var hasHideClass = sliderBubble.classList.contains('hide');
this.addEventListener('input', function (e) { dom.addEventListener(this, 'input', function (e) {
this.dragging = true; this.dragging = true;
});
this.addEventListener('change', function () {
this.dragging = false;
updateValues(this, backgroundLower, backgroundUpper);
});
this.addEventListener('mousemove', function (e) { updateBubble(this, this.value, sliderBubble, sliderBubbleText);
var rect = this.getBoundingClientRect();
var clientX = e.clientX;
var bubbleValue = (clientX - rect.left) / rect.width;
bubbleValue *= 100;
updateBubble(this, Math.round(bubbleValue), sliderBubble);
if (hasHideClass) { if (hasHideClass) {
sliderBubble.classList.remove('hide'); sliderBubble.classList.remove('hide');
hasHideClass = false; hasHideClass = false;
} }
}, {
passive: true
}); });
this.addEventListener('mouseleave', function () {
dom.addEventListener(this, 'change', function () {
this.dragging = false;
updateValues(this, backgroundLower, backgroundUpper);
sliderBubble.classList.add('hide'); sliderBubble.classList.add('hide');
hasHideClass = true; 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 (!supportsNativeProgressStyle) {
if (supportsValueSetOverride) { if (supportsValueSetOverride) {

View file

@ -8,7 +8,7 @@
width: auto; width: auto;
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
color: #aaa !important; color: #aaa;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
flex-shrink: 0; flex-shrink: 0;
@ -17,7 +17,7 @@
transition: none !important; transition: none !important;
position: relative; position: relative;
text-transform: uppercase; text-transform: uppercase;
font-weight: bold !important; font-weight: bold;
height: auto; height: auto;
min-width: initial; min-width: initial;
line-height: initial; line-height: initial;
@ -26,11 +26,11 @@
} }
.emby-tab-button:focus { .emby-tab-button:focus {
font-weight: bold !important; font-weight: bold;
} }
.emby-tab-button-active { .emby-tab-button-active {
color: #52B54B !important; color: #52B54B;
border-color: #52B54B; border-color: #52B54B;
} }

View file

@ -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'; 'use strict';
var EmbyTabs = Object.create(HTMLDivElement.prototype); 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) { function onClick(e) {
var tabs = this; var tabs = this;
@ -204,14 +221,37 @@
return; return;
} }
this.classList.add('emby-tabs'); this.classList.add('emby-tabs');
this.classList.add('focusable');
dom.addEventListener(this, 'click', onClick, { dom.addEventListener(this, 'click', onClick, {
passive: true passive: true
}); });
dom.addEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
initSelectionBar(this); 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 () { EmbyTabs.attachedCallback = function () {
initScroller(this); initScroller(this);
@ -236,6 +276,10 @@
dom.removeEventListener(this, 'click', onClick, { dom.removeEventListener(this, 'click', onClick, {
passive: true passive: true
}); });
dom.removeEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
this.selectionBar = null; this.selectionBar = null;
}; };

View file

@ -304,10 +304,12 @@ define(['dom'], function (dom) {
var nearestElement = nearest[0].node; var nearestElement = nearest[0].node;
// See if there's a focusable container, and if so, send the focus command to that // See if there's a focusable container, and if so, send the focus command to that
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); if (activeElement) {
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && activeElement) { var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
if (dom.parentWithClass(activeElement, 'focusable') !== nearestElementFocusableParent) { if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
nearestElement = nearestElementFocusableParent; if (focusableContainer !== nearestElementFocusableParent) {
nearestElement = nearestElementFocusableParent;
}
} }
} }
focus(nearestElement); focus(nearestElement);

View file

@ -51,7 +51,8 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
display: block; display: flex;
position: absolute;
padding: 1.25em 1em; padding: 1.25em 1em;
/* Without this emby-checkbox is able to appear on top */ /* Without this emby-checkbox is able to appear on top */
z-index: 1; z-index: 1;
@ -60,16 +61,9 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
@supports (display: flex) {
.formDialogFooter {
display: flex;
position: absolute;
}
}
.formDialogFooter-flex { .formDialogFooter-flex {
position: static; position: static;
width: 100%;
} }
.formDialogFooterItem { .formDialogFooterItem {

View file

@ -185,7 +185,13 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana
function translateKeyFromModule(key, module) { 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) { function replaceAll(str, find, replace) {

View file

@ -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
};
});

View file

@ -1,29 +0,0 @@
<div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</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>

View file

@ -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) { 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'; '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) { function save(context) {
var i, length; var i, length;
@ -65,7 +101,7 @@
} }
} }
function showEditor() { function showEditor(options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
@ -106,6 +142,7 @@
} }
save(dlg); save(dlg);
saveCategories(dlg, options);
if (settingsChanged) { if (settingsChanged) {
resolve(); resolve();
@ -123,6 +160,7 @@
} }
load(dlg); load(dlg);
loadCategories(dlg, options);
dialogHelper.open(dlg); dialogHelper.open(dlg);
}); });
}); });

View file

@ -40,8 +40,29 @@
</div> </div>
<br /> <br />
<label class="checkboxContainer"> <label class="checkboxContainer">
<input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds" /> <input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds"/>
<span>${EnableColorCodedBackgrounds}</span> <span>${EnableColorCodedBackgrounds}</span>
</label> </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> </form>
</div> </div>

View file

@ -7,9 +7,18 @@
.tvGuideHeader { .tvGuideHeader {
white-space: nowrap; white-space: nowrap;
width: 100%; width: 100%;
flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
padding-left: 3.4em; }
.guideHeaderDateSelection {
font-size: 86%;
padding: .4em 0;
}
.guideHeaderTimeslots {
display: flex;
} }
.tvProgramSectionHeader { .tvProgramSectionHeader {
@ -38,6 +47,7 @@
.channelTimeslotHeader { .channelTimeslotHeader {
flex-shrink: 0; flex-shrink: 0;
justify-content: center;
} }
.timeslotHeaders { .timeslotHeaders {
@ -49,6 +59,7 @@
position: relative; position: relative;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
flex-grow: 1;
} }
.channelPrograms { .channelPrograms {
@ -77,7 +88,7 @@
.currentTimeIndicatorArrowContainer { .currentTimeIndicatorArrowContainer {
position: absolute; position: absolute;
bottom: -1.3vh; bottom: -1vh;
width: 100%; width: 100%;
color: #52B54B; color: #52B54B;
margin-left: .65vh; margin-left: .65vh;
@ -91,11 +102,11 @@
} }
.currentTimeIndicatorArrow { .currentTimeIndicatorArrow {
width: 4vh; width: 3vh;
height: 4vh; height: 3vh;
font-size: 4vh; font-size: 3vh;
color: #52B54B; color: #52B54B;
margin-left: -2vh; margin-left: -1.5vh;
} }
.channelPrograms, .timeslotHeadersInner { .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 { .btnGuideViewSettings {
margin: 0; margin: 0;
flex-shrink: 0; flex-shrink: 0;
@ -203,13 +191,6 @@
font-size: 1.5em !important; font-size: 1.5em !important;
} }
@media all and (max-width: 1280px) {
.btnGuideViewSettings {
display: none;
}
}
.selectDateIcon { .selectDateIcon {
flex-shrink: 0; flex-shrink: 0;
} }
@ -258,11 +239,12 @@
} }
.timeslotHeader, .channelTimeslotHeader { .timeslotHeader, .channelTimeslotHeader {
height: 3em; height: 2.2em;
} }
.programGrid { .programGrid {
padding-bottom: 4px; padding-bottom: 4px;
flex-grow: 1;
} }
.timeslotHeader { .timeslotHeader {
@ -347,7 +329,7 @@
} }
.programTextIcon-tv { .programTextIcon-tv {
font-size: .7em; font-size: .6em;
} }
.guideChannelNumber { .guideChannelNumber {
@ -384,29 +366,6 @@
flex-shrink: 0; 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 { .channelList {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -416,11 +375,11 @@
contain: layout style; contain: layout style;
} }
.programCell, .channelHeaderCell, .btnSelectDate { .programCell, .channelHeaderCell {
outline: none !important; outline: none !important;
} }
.programCell:focus, .channelHeaderCell:focus, .btnSelectDate:focus { .programCell:focus, .channelHeaderCell:focus {
background-color: #555; background-color: #555;
} }
@ -433,25 +392,6 @@
opacity: .7; 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 { .guideOptions {
color: #eee; color: #eee;
flex-shrink: 0; flex-shrink: 0;
@ -464,8 +404,54 @@
.tvGuideHeader { .tvGuideHeader {
padding-left: 0; padding-left: 0;
} }
}
.btnCategories { .guideRequiresUnlock {
display: none; 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;
} }
} }

View file

@ -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'; 'use strict';
function showViewSettings(instance) { function showViewSettings(instance) {
require(['guide-settings-dialog'], function (guideSettingsDialog) { require(['guide-settings-dialog'], function (guideSettingsDialog) {
guideSettingsDialog.show().then(function () { guideSettingsDialog.show(instance.categoryOptions).then(function () {
instance.refresh();
});
});
}
function showCategoryOptions(instance) {
require(['guide-categories-dialog'], function (guideCategoriesDialog) {
guideCategoriesDialog.show(instance.categoryOptions).then(function (categoryOptions) {
instance.categoryOptions = categoryOptions;
instance.refresh(); instance.refresh();
}); });
}); });
@ -38,15 +27,31 @@
var currentDate; var currentDate;
var currentStartIndex = 0; var currentStartIndex = 0;
var currentChannelLimit = 0; var currentChannelLimit = 0;
var autoRefreshInterval;
self.refresh = function () { self.refresh = function () {
currentDate = null; currentDate = null;
reloadPage(options.element); reloadPage(options.element);
restartAutoRefresh();
};
self.pause = function () {
stopAutoRefresh();
};
self.resume = function (refreshData) {
if (refreshData) {
self.refresh();
} else {
restartAutoRefresh();
}
}; };
self.destroy = function () { self.destroy = function () {
stopAutoRefresh();
events.off(serverNotifications, 'TimerCreated', onTimerCreated); events.off(serverNotifications, 'TimerCreated', onTimerCreated);
events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated); events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated);
events.off(serverNotifications, 'TimerCancelled', onTimerCancelled); events.off(serverNotifications, 'TimerCancelled', onTimerCancelled);
@ -58,6 +63,24 @@
items = {}; 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) { function normalizeDateToTimeslot(date) {
var minutesOffset = date.getMinutes() - cellCurationMinutes; var minutesOffset = date.getMinutes() - cellCurationMinutes;
@ -152,7 +175,7 @@
}); });
} }
function reloadGuide(context, newStartDate) { function reloadGuide(context, newStartDate, focusProgramOnRender) {
var apiClient = connectionManager.currentApiClient(); var apiClient = connectionManager.currentApiClient();
@ -211,8 +234,8 @@
channelQuery.SortBy = "DatePlayed"; channelQuery.SortBy = "DatePlayed";
channelQuery.SortOrder = "Descending"; channelQuery.SortOrder = "Descending";
} else { } else {
channelQuery.SortBy = "SortName"; channelQuery.SortBy = null;
channelQuery.SortOrder = "Ascending"; channelQuery.SortOrder = null;
} }
var date = newStartDate; var date = newStartDate;
@ -267,7 +290,7 @@
}).then(function (programsResult) { }).then(function (programsResult) {
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient); renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient, focusProgramOnRender);
hideLoading(); hideLoading();
@ -482,7 +505,7 @@
timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"'; 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) { if (displayInnerContent) {
var guideProgramNameClass = "guideProgramName"; var guideProgramNameClass = "guideProgramName";
@ -605,7 +628,7 @@
imageLoader.lazyChildren(channelList); imageLoader.lazyChildren(channelList);
} }
function renderGuide(context, date, channels, programs, apiClient) { function renderGuide(context, date, channels, programs, apiClient, focusProgramOnRender) {
//var list = []; //var list = [];
//channels.forEach(function(i) { //channels.forEach(function(i) {
@ -663,7 +686,7 @@
items = {}; items = {};
renderPrograms(context, date, channels, programs); renderPrograms(context, date, channels, programs);
if (layoutManager.tv) { if (focusProgramOnRender) {
var focusElem; var focusElem;
if (itemId) { if (itemId) {
@ -723,21 +746,30 @@
} }
} }
function changeDate(page, date) { function changeDate(page, date, focusProgramOnRender) {
clearCurrentTimeUpdateInterval(); clearCurrentTimeUpdateInterval();
var newStartDate = normalizeDateToTimeslot(date); var newStartDate = normalizeDateToTimeslot(date);
currentDate = newStartDate; currentDate = newStartDate;
reloadGuide(page, newStartDate); reloadGuide(page, newStartDate, focusProgramOnRender);
var dateText = datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' });
page.querySelector('.guideDateText').innerHTML = dateText;
} }
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) { function setDateRange(page, guideInfo) {
@ -756,18 +788,8 @@
start = new Date(Math.max(today, start)); start = new Date(Math.max(today, start));
dateOptions = []; var dateTabsHtml = '';
var tabIndex = 0;
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 date = new Date(); var date = new Date();
@ -775,7 +797,21 @@
date.setTime(currentDate.getTime()); 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) { 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) { function setScrollEvents(view, enabled) {
if (layoutManager.tv) { if (layoutManager.tv) {
require(['scrollHelper'], function (scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = enabled ? 'on' : 'off'; 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); scrollHelper.centerFocus[fn](view.querySelector('.programGrid'), true);
}); });
} }
@ -903,9 +916,9 @@
context.innerHTML = globalize.translateDocument(template, 'sharedcomponents'); context.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
if (layoutManager.desktop) { if (layoutManager.desktop) {
var visibleGuideScrollers = context.querySelectorAll('.guideScroller'); var guideScrollers = context.querySelectorAll('.guideScroller');
for (var i = 0, length = visibleGuideScrollers.length; i < length; i++) { for (var i = 0, length = guideScrollers.length; i < length; i++) {
visibleGuideScrollers[i].classList.add('visibleGuideScroller'); guideScrollers[i].classList.add('darkScroller');
} }
} }
@ -914,6 +927,16 @@
programGrid.addEventListener('focus', onProgramGridFocus, true); 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) { dom.addEventListener(programGrid, 'scroll', function (e) {
onProgramGridScroll(context, this, timeslotHeaders); onProgramGridScroll(context, this, timeslotHeaders);
}, { }, {
@ -926,31 +949,37 @@
passive: true passive: true
}); });
context.querySelector('.btnSelectDate').addEventListener('click', function () {
selectDate(context);
});
context.querySelector('.btnUnlockGuide').addEventListener('click', function () { context.querySelector('.btnUnlockGuide').addEventListener('click', function () {
currentStartIndex = 0; currentStartIndex = 0;
reloadPage(context); reloadPage(context);
restartAutoRefresh();
}); });
context.querySelector('.btnNextPage').addEventListener('click', function () { context.querySelector('.btnNextPage').addEventListener('click', function () {
currentStartIndex += currentChannelLimit; currentStartIndex += currentChannelLimit;
reloadPage(context); reloadPage(context);
restartAutoRefresh();
}); });
context.querySelector('.btnPreviousPage').addEventListener('click', function () { context.querySelector('.btnPreviousPage').addEventListener('click', function () {
currentStartIndex = Math.max(currentStartIndex - currentChannelLimit, 0); currentStartIndex = Math.max(currentStartIndex - currentChannelLimit, 0);
reloadPage(context); reloadPage(context);
restartAutoRefresh();
}); });
context.querySelector('.btnGuideViewSettings').addEventListener('click', function () { context.querySelector('.btnGuideViewSettings').addEventListener('click', function () {
showViewSettings(self); showViewSettings(self);
restartAutoRefresh();
}); });
context.querySelector('.btnCategories').addEventListener('click', function () { context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
showCategoryOptions(self);
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'); context.classList.add('tvguide');

View file

@ -1,36 +1,33 @@
<div class="tvGuideHeader"> <div class="tvGuideHeader">
<div class="channelTimeslotHeader">
<button is="emby-button" type="button" class="btnSelectDate block button-flat" style="color:inherit;"> <div class="guideHeaderDateSelection">
<div class="btnSelectDateContent"> <div is="emby-tabs" class="guideDateTabs" data-selectionbar="false">
<div class="guideDateText"> <div class="emby-tabs-slider guideDateTabsSlider">
</div>
<i class="md-icon selectDateIcon">&#xE5C5;</i>
</div> </div>
</button> </div>
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
<i class="md-icon btnGuideViewSettingsIcon">&#xE42A;</i>
</button>
</div> </div>
<div class="timeslotHeaders smoothScrollX guideScroller" style="scroll-behavior: auto;"></div>
</div>
<div style="display: flex;flex-grow:1;overflow:hidden;"> <div class="guideHeaderTimeslots">
<div class="channelTimeslotHeader">
<button is="emby-button" type="button" class="btnCategories"> <button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
<div class="btnCategoriesText">${Categories}</div> <i class="md-icon btnGuideViewSettingsIcon">&#xE5D3;</i>
</button> </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> </div>
<div class="timeslotHeaders smoothScrollX guideScroller" style="scroll-behavior: auto;"></div>
</div> </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> <p class="unlockText"></p>
<button is="emby-button" type="button" class="raised button-submit block btnUnlockGuide"> <button is="emby-button" type="button" class="raised button-submit block btnUnlockGuide">
<span>${UnlockGuide}</span> <span>${UnlockGuide}</span>

View 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;
}
}());

View 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%;
}
}

View file

@ -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'; 'use strict';
var currentItem; var currentItem;

View file

@ -1,14 +1,4 @@
<style> <div class="formDialogHeader">
@media all and (min-width: 1200px) {
.imageEditorCard {
width: 20%;
}
}
</style>
<div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button> <button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>
<h3 class="formDialogHeaderTitle"> <h3 class="formDialogHeaderTitle">
${HeaderEditImages} ${HeaderEditImages}
@ -19,7 +9,7 @@
<div class="dialogContentInner"> <div class="dialogContentInner">
<div id="imagesContainer"> <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> <h1 style="margin:0;">${Images}</h1>
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;"> <button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;">
<i class="md-icon">search</i> <i class="md-icon">search</i>
@ -34,7 +24,7 @@
</div> </div>
<div id="backdropsContainer" class="hide"> <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> <h1 style="margin:0;">${Backdrops}</h1>
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Backdrop"> <button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Backdrop">
<i class="md-icon">search</i> <i class="md-icon">search</i>
@ -49,7 +39,7 @@
</div> </div>
<div id="screenshotsContainer" class="hide"> <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> <h1 style="margin: 0;">${Screenshots}</h1>
<button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Screenshot"> <button type="button" is="emby-button" class="btnBrowseAllImages fab mini autoSize" style="margin-left: 1em;" data-imagetype="Screenshot">
<i class="md-icon">search</i> <i class="md-icon">search</i>

View file

@ -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'; 'use strict';
var thresholdX;
var thresholdY;
var requestIdleCallback = window.requestIdleCallback || function (fn) { var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn(); fn();
}; };
//var imagesWorker = new Worker(require.toUrl('.').split('?')[0] + '/imagesworker.js'); //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 self = {};
var enableFade = browser.animate && !browser.slow; var enableFade = browser.animate && !browser.slow;
@ -65,7 +27,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
function fillImageElement(elem, source, enableEffects) { function fillImageElement(elem, source, enableEffects) {
imageFetcher.loadImage(elem, source).then(function () { 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) { if (enableFade && !layoutManager.tv && enableEffects !== false && !fillingVibrant) {
fadeIn(elem); fadeIn(elem);
@ -148,14 +110,17 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
requestIdleCallback(function () { requestIdleCallback(function () {
//var now = new Date().getTime(); //var now = new Date().getTime();
var swatch = getVibrantInfo(img, url).split('|'); getVibrantInfoFromElement(img, url).then(function (vibrantInfo) {
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
if (swatch.length) {
var index = 0; var swatch = vibrantInfo.split('|');
vibrantElement.style.backgroundColor = swatch[index]; //console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
vibrantElement.style.color = swatch[index + 1]; if (swatch.length) {
}
var index = 0;
vibrantElement.style.backgroundColor = swatch[index];
vibrantElement.style.color = swatch[index + 1];
}
});
}); });
/* /*
* Results into: * 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) { function getSettingsKey(url) {
var parts = url.split('://'); var parts = url.split('://');
@ -176,7 +161,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
url = url.split('?')[0]; url = url.split('?')[0];
var cacheKey = 'vibrant25'; var cacheKey = 'vibrant31';
//cacheKey = 'vibrant' + new Date().getTime(); //cacheKey = 'vibrant' + new Date().getTime();
return cacheKey + url; return cacheKey + url;
} }
@ -198,33 +183,21 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
value = ''; value = '';
var swatch = swatches.DarkVibrant; var swatch = swatches.DarkVibrant;
if (swatch) { value += getSwatchString(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 += '||';
//}
appSettings.set(getSettingsKey(url), value); appSettings.set(getSettingsKey(url), value);
return value; return value;
} }
function getSwatchString(swatch) {
if (swatch) {
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
}
return '||';
}
function fadeIn(elem) { function fadeIn(elem) {
var duration = layoutManager.tv ? 160 : 300; var duration = layoutManager.tv ? 160 : 300;
@ -236,135 +209,9 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
elem.animate(keyframes, timing); 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) { function lazyChildren(elem) {
unveilElements(elem.getElementsByClassName('lazy'), elem); lazyLoader.lazyChildren(elem, fillImage);
} }
function getPrimaryImageAspectRatio(items) { function getPrimaryImageAspectRatio(items) {
@ -439,6 +286,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
self.lazyChildren = lazyChildren; self.lazyChildren = lazyChildren;
self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio; self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio;
self.getCachedVibrantInfo = getCachedVibrantInfo; self.getCachedVibrantInfo = getCachedVibrantInfo;
self.getVibrantInfoFromElement = getVibrantInfoFromElement;
return self; return self;
}); });

View file

@ -14,7 +14,6 @@
.indicator { .indicator {
border-radius: 500px; border-radius: 500px;
display: -ms-flex;
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;
@ -45,7 +44,6 @@
.countIndicator { .countIndicator {
background: rgba(82,181,75,1); background: rgba(82,181,75,1);
border-radius: 500px; border-radius: 500px;
display: -ms-flex;
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;
@ -57,7 +55,6 @@
.playedIndicator { .playedIndicator {
background: rgba(82,181,75,1); background: rgba(82,181,75,1);
border-radius: 500px; border-radius: 500px;
display: -ms-flex;
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;

View file

@ -49,13 +49,30 @@ define(['css!./indicators.css', 'material-icons'], function () {
function enablePlayedIndicator(item) { 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') { if (item.Type !== 'TvChannel') {
return true; 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; return false;
} }

View file

@ -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') { if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
commands.push({ 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({ commands.push({
name: Globalize.translate('sharedcomponents#Record'), name: Globalize.translate('sharedcomponents#Record'),
@ -184,7 +184,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
if (user.Policy.IsAdministrator) { 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({ commands.push({
name: globalize.translate('sharedcomponents#Refresh'), name: globalize.translate('sharedcomponents#Refresh'),
id: '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({ commands.push({
name: Globalize.translate('sharedcomponents#ViewAlbum'), name: Globalize.translate('sharedcomponents#ViewAlbum'),
id: 'album' id: 'album'
@ -577,25 +577,16 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var itemId = item.Id; require(['deleteHelper'], function (deleteHelper) {
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem'); deleteHelper.deleteItem({
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
item: item,
require(['confirm'], function (confirm) { navigate: false
confirm({
title: title,
text: msg,
confirmText: globalize.translate('sharedcomponents#Delete'),
primary: 'cancel'
}).then(function () { }).then(function () {
apiClient.deleteItem(itemId).then(function () { resolve(true);
resolve(true);
});
}, reject); }, reject);

View file

@ -13,7 +13,7 @@ define(['apphost'], function (appHost) {
item = item.ProgramInfo || item; 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") { if (item.Type === "TvChannel") {
@ -30,10 +30,10 @@ define(['apphost'], function (appHost) {
var displayIndexNumber = item.IndexNumber; var displayIndexNumber = item.IndexNumber;
var number = "E" + displayIndexNumber; var number = displayIndexNumber;
if (options.includeParentInfo !== false) { if (options.includeParentInfo !== false) {
number = "S" + item.ParentIndexNumber + ", " + number; number = "S" + item.ParentIndexNumber + ", E" + number;
} }
if (item.IndexNumberEnd) { if (item.IndexNumberEnd) {
@ -71,6 +71,9 @@ define(['apphost'], function (appHost) {
if (item.Type === 'Program') { if (item.Type === 'Program') {
return false; return false;
} }
if (item.Type === 'TvChannel') {
return false;
}
if (item.Type === 'Timer') { if (item.Type === 'Timer') {
return false; return false;
} }
@ -169,6 +172,12 @@ define(['apphost'], function (appHost) {
canShare: function (user, item) { canShare: function (user, item) {
if (item.Type === 'Program') {
return false;
}
if (item.Type === 'TvChannel') {
return false;
}
if (item.Type === 'Timer') { if (item.Type === 'Timer') {
return false; return false;
} }
@ -181,6 +190,10 @@ define(['apphost'], function (appHost) {
} }
} }
return user.Policy.EnablePublicSharing && appHost.supports('sharing'); return user.Policy.EnablePublicSharing && appHost.supports('sharing');
},
enableDateAddedDisplay: function(item) {
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
} }
}; };
}); });

View file

@ -33,7 +33,6 @@
} }
.cardOverlayFab { .cardOverlayFab {
background-color: #282828 !important;
margin-right: .25em !important; margin-right: .25em !important;
} }

View 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;
});

View 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;
});

View file

@ -100,8 +100,8 @@
} }
.listItemIcon { .listItemIcon {
width: auto !important; width: 1em !important;
height: auto !important; height: 1em !important;
font-size: 143%; font-size: 143%;
border-radius: 500px; border-radius: 500px;
background-color: #52B54B; background-color: #52B54B;
@ -166,12 +166,9 @@
align-items: center; align-items: center;
} }
@supports (display: flex) { .listItem, .listItemBody, .listItemMediaInfo {
display: flex;
.listItem, .listItemBody, .listItemMediaInfo { contain: layout style;
display: flex;
contain: layout style;
}
} }
@media all and (max-width: 800px) { @media all and (max-width: 800px) {

View file

@ -310,7 +310,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
textlines.push(displayName); textlines.push(displayName);
} }
if (options.artist !== false) { if (options.artist !== false && (options.artist === true || item.AlbumArtist !== options.containerAlbumArtist)) {
if (item.ArtistItems && item.Type !== 'MusicAlbum') { if (item.ArtistItems && item.Type !== 'MusicAlbum') {
textlines.push(item.ArtistItems.map(function (a) { textlines.push(item.ArtistItems.map(function (a) {
return a.Name; return a.Name;
@ -318,7 +319,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}).join(', ')); }).join(', '));
} }
if (item.AlbumArtist && item.Type === 'MusicAlbum') { else if (item.AlbumArtist && item.Type === 'MusicAlbum') {
textlines.push(item.AlbumArtist); textlines.push(item.AlbumArtist);
} }
} }

View file

@ -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 { try {
date = datetime.parseISO8601Date(item.StartDate); date = datetime.parseISO8601Date(item.StartDate);
@ -453,6 +469,160 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
return ''; 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 { return {
getMediaInfoHtml: getPrimaryMediaInfoHtml, getMediaInfoHtml: getPrimaryMediaInfoHtml,
fill: fillPrimaryMediaInfo, fill: fillPrimaryMediaInfo,
@ -461,6 +631,7 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml, getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml,
getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml, getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml,
fillPrimaryMediaInfo: fillPrimaryMediaInfo, fillPrimaryMediaInfo: fillPrimaryMediaInfo,
fillSecondaryMediaInfo: fillSecondaryMediaInfo fillSecondaryMediaInfo: fillSecondaryMediaInfo,
getMediaInfoStats: getMediaInfoStats
}; };
}); });

View file

@ -700,14 +700,14 @@
showElement('#fldCustomRating', context); showElement('#fldCustomRating', context);
} }
showElement('#tagsCollapsible', context);
if (item.Type === "TvChannel") { if (item.Type === "TvChannel") {
hideElement('#tagsCollapsible', context);
hideElement('#metadataSettingsCollapsible', context); hideElement('#metadataSettingsCollapsible', context);
hideElement('#fldPremiereDate', context); hideElement('#fldPremiereDate', context);
hideElement('#fldDateAdded', context); hideElement('#fldDateAdded', context);
hideElement('#fldYear', context); hideElement('#fldYear', context);
} else { } else {
showElement('#tagsCollapsible', context);
showElement('#metadataSettingsCollapsible', context); showElement('#metadataSettingsCollapsible', context);
showElement('#fldPremiereDate', context); showElement('#fldPremiereDate', context);
showElement('#fldDateAdded', context); showElement('#fldDateAdded', context);

View file

@ -5,7 +5,7 @@
(function UMD(name,context,definition){ (function UMD(name,context,definition){
// special form of UMD for polyfilling across evironments // 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]; } if (typeof module != "undefined" && module.exports) { module.exports = context[name]; }
else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); } else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); }
})("Promise",typeof global != "undefined" ? global : this,function DEF(){ })("Promise",typeof global != "undefined" ? global : this,function DEF(){

View file

@ -139,7 +139,8 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
Filters: "IsNotFolder", Filters: "IsNotFolder",
SortBy: "DateCreated", SortBy: "DateCreated",
SortOrder: "Descending", SortOrder: "Descending",
Ids: newItems.join(',') Ids: newItems.join(','),
MediaTypes: "Audio,Video"
}).then(function (result) { }).then(function (result) {

View file

@ -127,6 +127,12 @@
select.innerHTML = html; select.innerHTML = html;
select.value = userSettings.get('playlisteditor-lastplaylistid') || ''; 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); triggerChange(select);
loading.hide(); loading.hide();

View file

@ -19,4 +19,18 @@
.recordingDialog-btnRecord { .recordingDialog-btnRecord {
background-color: #cc3333; background-color: #cc3333;
} }
.recordingDetailsContainer {
display: flex;
}
.recordingDetails {
flex-grow: 1;
}
.recordingDetailText {
display: flex;
align-items: center;
flex-wrap: wrap;
}

View file

@ -5,14 +5,14 @@
<div class="formDialogContent smoothScrollY"> <div class="formDialogContent smoothScrollY">
<form class="dialogContentInner dialog-content-centered"> <form class="dialogContentInner dialog-content-centered">
<div style="display: flex;"> <div class="recordingDetailsContainer">
<div class="recordingDialog-imageContainer"> <div class="recordingDialog-imageContainer">
</div> </div>
<div style="flex-grow: 1;"> <div class="recordingDetails">
<h1 class="programDialog-itemName recordingDialog-itemName dialogContentTitle"></h1> <h1 class="programDialog-itemName recordingDialog-itemName dialogContentTitle"></h1>
<p class="itemMiscInfoPrimary" style="display: flex; align-items: center; flex-wrap: wrap;"></p> <p class="itemMiscInfoPrimary recordingDetailText"></p>
<p class="itemMiscInfoSecondary secondaryText" style="display: flex; align-items: center; flex-wrap: wrap;"></p> <p class="itemMiscInfoSecondary recordingDetailText secondaryText"></p>
<p class="itemGenres secondaryText"></p> <p class="itemGenres secondaryText"></p>
<div style="margin:.5em 0 1em;" class="recordingFields"> <div style="margin:.5em 0 1em;" class="recordingFields">

View 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;
}
}

View file

@ -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'; 'use strict';
function getRegistration(apiClient, programId, feature) { function getRegistration(apiClient, programId, feature) {
@ -106,21 +106,21 @@
} }
if (program.SeriesTimerId) { 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 .recordingIcon').classList.add('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#CancelSeries'); parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#CancelSeries');
} else { } else {
parent.querySelector('.btnManageSeriesRecording').classList.add('visibilityHide'); parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active'); parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#RecordSeries'); parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#RecordSeries');
} }
if (program.TimerId && program.Status !== 'Cancelled') { 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 .recordingIcon').classList.add('recordingIcon-active');
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#DoNotRecord'); parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#DoNotRecord');
} else { } else {
parent.querySelector('.btnManageRecording').classList.add('visibilityHide'); parent.querySelector('.btnManageRecording').classList.add('hide');
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active'); parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#Record'); parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('sharedcomponents#Record');
} }

View file

@ -1,47 +1,4 @@
<style> <div class="convertRecordingsContainer hide" style="padding: 1.25em 1.5em; background: #242424; border-radius: 3px; margin: 1em 0 2em;">
.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;">
<h1 style="margin: .25em 0 .5em;">${HeaderConvertYourRecordings}</h1> <h1 style="margin: .25em 0 .5em;">${HeaderConvertYourRecordings}</h1>
<div class="fieldDescription">${PromoConvertRecordingsToStreamingFormat}</div> <div class="fieldDescription">${PromoConvertRecordingsToStreamingFormat}</div>
<br /> <br />
@ -58,27 +15,27 @@
</div> </div>
<div class="recordingFields hide"> <div class="recordingFields hide">
<div class="recordSeriesContainer hide" style="display: flex; align-items: center;margin-bottom:.8em;"> <div class="recordSeriesContainer recordingFields-buttons hide">
<div> <div>
<button is="emby-button" type="button" class="raised button-cancel recordingButton seriesRecordingButton"> <button is="emby-button" type="button" class="raised button-cancel recordingButton seriesRecordingButton">
<i class="md-icon recordingIcon">&#xE062;</i> <i class="md-icon recordingIcon">&#xE062;</i>
<span class="buttonText">${RecordSeries}</span> <span class="buttonText">${RecordSeries}</span>
</button> </button>
</div> </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> <i class="md-icon manageButtonIcon">settings</i>
<span class="manageButtonText">${SeriesSettings}</span> <span class="manageButtonText">${SeriesSettings}</span>
</button> </button>
</div> </div>
<div style="display: flex; align-items: center;"> <div class="recordingFields-buttons">
<div> <div>
<button is="emby-button" type="button" class="raised button-cancel recordingButton singleRecordingButton"> <button is="emby-button" type="button" class="raised button-cancel recordingButton singleRecordingButton">
<i class="md-icon recordingIcon">&#xE061;</i> <i class="md-icon recordingIcon">&#xE061;</i>
<span class="buttonText">${Record}</span> <span class="buttonText">${Record}</span>
</button> </button>
</div> </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> <i class="md-icon manageButtonIcon">settings</i>
<span class="manageButtonText">${Settings}</span> <span class="manageButtonText">${Settings}</span>
</button> </button>

View file

@ -1,4 +1,4 @@
define(['globalize', 'loading'], function (globalize, loading) { define(['globalize', 'loading', 'connectionManager'], function (globalize, loading, connectionManager) {
'use strict'; 'use strict';
function changeRecordingToSeries(apiClient, timerId, programId) { function changeRecordingToSeries(apiClient, timerId, programId) {

View file

@ -98,15 +98,24 @@
function reload(context, id) { function reload(context, id) {
loading.show();
currentItemId = id;
var apiClient = connectionManager.getApiClient(currentServerId); 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(); loading.hide();
}); }
} }
function fillKeepUpTo(context) { function fillKeepUpTo(context) {
@ -130,6 +139,10 @@
context.querySelector('.selectKeepUpTo').innerHTML = html; context.querySelector('.selectKeepUpTo').innerHTML = html;
} }
function onFieldChange(e) {
this.querySelector('.btnSubmit').click();
}
function embed(itemId, serverId, options) { function embed(itemId, serverId, options) {
@ -163,9 +176,8 @@
dlg.querySelector('.dialogContentInner').className = ''; dlg.querySelector('.dialogContentInner').className = '';
dlg.classList.remove('hide'); dlg.classList.remove('hide');
dlg.addEventListener('change', function () { dlg.removeEventListener('change', onFieldChange);
dlg.querySelector('.btnSubmit').click(); dlg.addEventListener('change', onFieldChange);
});
currentDialog = dlg; currentDialog = dlg;

View file

@ -8,7 +8,7 @@
<div class="formDialogContent smoothScrollY"> <div class="formDialogContent smoothScrollY">
<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;"> <div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">
<form> <form style="max-width: none;">
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" class="selectShowType" label="${LabelRecord}"> <select is="emby-select" class="selectShowType" label="${LabelRecord}">
<option value="new">${NewEpisodesOnly}</option> <option value="new">${NewEpisodesOnly}</option>
@ -18,7 +18,7 @@
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input type="checkbox" is="emby-checkbox" class="chkSkipEpisodesInLibrary"/> <input type="checkbox" is="emby-checkbox" class="chkSkipEpisodesInLibrary" />
<span>${SkipEpisodesAlreadyInMyLibrary}</span> <span>${SkipEpisodesAlreadyInMyLibrary}</span>
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${SkipEpisodesAlreadyInMyLibraryHelp}</div> <div class="fieldDescription checkboxFieldDescription">${SkipEpisodesAlreadyInMyLibraryHelp}</div>
@ -39,8 +39,7 @@
</div> </div>
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" class="selectKeepUpTo" label="${LabelKeepUpTo}"> <select is="emby-select" class="selectKeepUpTo" label="${LabelKeepUpTo}"></select>
</select>
</div> </div>
<div class="inputContainer"> <div class="inputContainer">

View file

@ -42,7 +42,7 @@
html += '<br />'; html += '<br />';
html += '<div class="formDialogFooter">'; 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 += '</div>';
html += '</form>'; html += '</form>';

View file

@ -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'; 'use strict';
var embyRouter = { var embyRouter = {
@ -491,16 +491,12 @@ define(['loading', 'dom', 'viewManager', 'skinManager', 'pluginManager', 'backdr
} }
var resolveOnNextShow; var resolveOnNextShow;
dom.addEventListener(document, 'viewshow', function () { document.addEventListener('viewshow', function () {
var resolve = resolveOnNextShow; var resolve = resolveOnNextShow;
if (resolve) { if (resolve) {
resolveOnNextShow = null; resolveOnNextShow = null;
resolve(); resolve();
} }
}, {
passive: true,
once: true
}); });
var currentRouteInfo; var currentRouteInfo;

View file

@ -873,6 +873,11 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'scrollStyles'], func
} }
} else { } else {
slideeElement.style['will-change'] = 'transform'; slideeElement.style['will-change'] = 'transform';
if (o.horizontal) {
slideeElement.classList.add('animatedScrollX');
} else {
slideeElement.classList.add('animatedScrollY');
}
} }
dragSourceElement.addEventListener('mousedown', dragInitSlidee); dragSourceElement.addEventListener('mousedown', dragInitSlidee);

View file

@ -33,3 +33,22 @@
width: 0 !important; width: 0 !important;
display: none; 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;
}

View file

@ -225,6 +225,8 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
var serverId = item.ServerId; var serverId = item.ServerId;
var type = item.Type; var type = item.Type;
var playableItemId = type === 'Program' ? item.ChannelId : item.Id;
if (action === 'link') { if (action === 'link') {
showItem(item, { showItem(item, {
@ -238,7 +240,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
} }
else if (action === 'instantmix') { else if (action === 'instantmix') {
playbackManager.instantMix(id, serverId); playbackManager.instantMix(playableItemId, serverId);
} }
else if (action === 'play') { else if (action === 'play') {
@ -246,7 +248,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0'); var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
playbackManager.play({ playbackManager.play({
ids: [id], ids: [playableItemId],
startPositionTicks: startPositionTicks, startPositionTicks: startPositionTicks,
serverId: serverId 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 { return {
on: on, on: on,
off: off, off: off,
onClick: onClick, onClick: onClick,
showContextMenu: showContextMenu showContextMenu: showContextMenu,
getShortcutAttributesHtml: getShortcutAttributesHtml
}; };
}); });

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Opcions de Visualitzaci\u00f3", "HeaderDisplaySettings": "Opcions de Visualitzaci\u00f3",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Ordre de visualitzaci\u00f3:", "LabelDisplayOrder": "Ordre de visualitzaci\u00f3:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -1,37 +1,37 @@
{ {
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.", "MessageUnlockAppWithPurchaseOrSupporter": "Odemknout tuto funkci pomoc\u00ed jednor\u00e1zov\u00e9 platby, nebo pomoc\u00ed aktivace p\u0159edplatn\u00e9ho Emby Premiere.",
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.", "MessageUnlockAppWithSupporter": "Odemknout tuto funkci pomoc\u00ed aktivn\u00edho p\u0159edplatn\u00e9ho 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.", "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": "Special - {0}", "ValueSpecialEpisodeName": "Speci\u00e1l - {0}",
"Share": "Share", "Share": "Sd\u00edlet",
"Add": "P\u0159idat", "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}", "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.", "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", "AttributeNew": "Nov\u00e9",
"Premiere": "Premiere", "Premiere": "Premi\u00e9ra",
"Live": "Live", "Live": "\u017div\u011b",
"Repeat": "Opakovat", "Repeat": "Opakovat",
"TrackCount": "{0} tracks", "TrackCount": "{0} stop",
"ItemCount": "{0} polo\u017eek", "ItemCount": "{0} polo\u017eek",
"ReleaseYearValue": "Release year: {0}", "ReleaseYearValue": "Rok vyd\u00e1n\u00ed: {0}",
"OriginalAirDateValue": "Original air date: {0}", "OriginalAirDateValue": "Datum vys\u00edl\u00e1n\u00ed origin\u00e1lu: {0}",
"EndsAtValue": "Ends at {0}", "EndsAtValue": "Kon\u010d\u00ed v {0}",
"OptionSundayShort": "Sun", "OptionSundayShort": "Ned",
"OptionMondayShort": "Mon", "OptionMondayShort": "Pon",
"OptionTuesdayShort": "Tue", "OptionTuesdayShort": "\u00date",
"OptionWednesdayShort": "Wed", "OptionWednesdayShort": "St\u0159",
"OptionThursdayShort": "Thu", "OptionThursdayShort": "\u010ctv",
"OptionFridayShort": "Fri", "OptionFridayShort": "P\u00e1t",
"OptionSaturdayShort": "Sat", "OptionSaturdayShort": "Sob",
"HeaderSelectDate": "Vyber datum", "HeaderSelectDate": "Vyber datum",
"ButtonOk": "Ok", "ButtonOk": "Ok",
"ButtonCancel": "Zru\u0161it", "ButtonCancel": "Zru\u0161it",
"ButtonGotIt": "M\u00e1m to", "ButtonGotIt": "M\u00e1m to",
"ButtonRestart": "Restart", "ButtonRestart": "Restart",
"RecordingCancelled": "Nahr\u00e1v\u00e1n\u00ed zru\u0161eno.", "RecordingCancelled": "Nahr\u00e1v\u00e1n\u00ed zru\u0161eno.",
"SeriesCancelled": "Series cancelled.", "SeriesCancelled": "S\u00e9rie zru\u0161ena.",
"RecordingScheduled": "Pl\u00e1n nahr\u00e1v\u00e1n\u00ed.", "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", "HeaderNewRecording": "Nov\u00fd z\u00e1znam",
"Sunday": "Ned\u011ble", "Sunday": "Ned\u011ble",
"Monday": "Pond\u011bl\u00ed", "Monday": "Pond\u011bl\u00ed",
@ -41,23 +41,23 @@
"Friday": "P\u00e1tek", "Friday": "P\u00e1tek",
"Saturday": "Sobota", "Saturday": "Sobota",
"Days": "Dny", "Days": "Dny",
"RecordSeries": "Record series", "RecordSeries": "Nahr\u00e1t s\u00e9rie",
"HeaderCinemaMode": "Cinema Mode", "HeaderCinemaMode": "Cinema M\u00f3d",
"HeaderCloudSync": "Cloud Sync", "HeaderCloudSync": "Synchronizace s Cloudem",
"HeaderOfflineDownloads": "Offline Media", "HeaderOfflineDownloads": "Offline m\u00e9dia",
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", "HeaderOfflineDownloadsDescription": "St\u00e1hnout m\u00e9dia do va\u0161eho za\u0159\u00edzen\u00ed pro snadn\u00e9 pou\u017eit\u00ed offline.",
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", "CloudSyncFeatureDescription": "Synchronizujte va\u0161e m\u00e9dia na cloud pro jednodu\u0161\u0161\u00ed z\u00e1lohov\u00e1n\u00ed, archivaci a konverzi.",
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.", "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": "Cover Art", "CoverArt": "Obal",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", "CinemaModeFeatureDescription": "S re\u017eimem Kino z\u00edskate funkci, kter\u00e1 p\u0159ed hlavn\u00edm programem p\u0159ehraje trailery a u\u017eivatelsk\u00e1 intra.",
"HeaderFreeApps": "Free Emby Apps", "HeaderFreeApps": "Emby Apps zdarma",
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", "FreeAppsFeatureDescription": "U\u017eijte si v\u00fdb\u011br Emby aplikac\u00ed zdarma pro va\u0161e za\u0159\u00edzen\u00ed.",
"HeaderBecomeProjectSupporter": "Z\u00edskat Emby Premiere", "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.", "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:", "LabelEmailAddress": "E-mailov\u00e1 adresa:",
"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.", "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.", "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", "Record": "Nahr\u00e1vat",
"Save": "Ulo\u017eit", "Save": "Ulo\u017eit",
"Edit": "Upravit", "Edit": "Upravit",
@ -67,38 +67,38 @@
"HeaderDeleteItem": "Smazat polo\u017eku", "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?", "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", "Refresh": "Obnovit",
"RefreshQueued": "Refresh queued.", "RefreshQueued": "Obnoven\u00ed za\u0159azeno.",
"AddToCollection": "Add to collection", "AddToCollection": "P\u0159idat do kolekce",
"HeaderAddToCollection": "P\u0159idat do Kolekce", "HeaderAddToCollection": "P\u0159idat do Kolekce",
"NewCollection": "Nov\u00e1 kolekce", "NewCollection": "Nov\u00e1 kolekce",
"LabelCollection": "Collection:", "LabelCollection": "Kolekce:",
"Help": "N\u00e1pov\u011bda", "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.", "SearchForCollectionInternetMetadata": "Vyhledat metadata a obr\u00e1zky na Internetu.",
"LabelName": "Jm\u00e9no:", "LabelName": "Jm\u00e9no:",
"NewCollectionNameExample": "P\u0159\u00edklad: Kolekce Star Wars", "NewCollectionNameExample": "P\u0159\u00edklad: Kolekce Star Wars",
"MessageItemsAdded": "Items added.", "MessageItemsAdded": "Polo\u017eka p\u0159id\u00e1na.",
"OptionNew": "Nov\u00fd...", "OptionNew": "Nov\u00fd...",
"LabelPlaylist": "Playlist:", "LabelPlaylist": "Playlist:",
"AddToPlaylist": "P\u0159idat do playlistu", "AddToPlaylist": "P\u0159idat do playlistu",
"HeaderAddToPlaylist": "P\u0159idat do playlistu", "HeaderAddToPlaylist": "P\u0159idat do playlistu",
"Subtitles": "Subtitles", "Subtitles": "Titulky",
"SearchForSubtitles": "Vyhledat titulky", "SearchForSubtitles": "Vyhledat titulky",
"LabelLanguage": "Jazyk:", "LabelLanguage": "Jazyk:",
"Search": "Vyhled\u00e1v\u00e1n\u00ed", "Search": "Vyhled\u00e1v\u00e1n\u00ed",
"NoSubtitleSearchResultsFound": "No results found.", "NoSubtitleSearchResultsFound": "\u017d\u00e1dn\u00e9 v\u00fdsledky.",
"File": "Soubor", "File": "Soubor",
"MessageAreYouSureDeleteSubtitles": "Jste si jisti, \u017ee chcete smazat tyto titulky?", "MessageAreYouSureDeleteSubtitles": "Jste si jisti, \u017ee chcete smazat tyto titulky?",
"ConfirmDeletion": "Potvrdit smaz\u00e1n\u00ed", "ConfirmDeletion": "Potvrdit smaz\u00e1n\u00ed",
"MySubtitles": "My Subtitles", "MySubtitles": "M\u00e9 titulky",
"MessageDownloadQueued": "Download queued.", "MessageDownloadQueued": "Sta\u017een\u00ed za\u0159azeno.",
"EditSubtitles": "Editovat titulky", "EditSubtitles": "Editovat titulky",
"UnlockGuide": "Pr\u016fvodce pro odem\u010den\u00ed", "UnlockGuide": "Pr\u016fvodce pro odem\u010den\u00ed",
"RefreshMetadata": "Obnovit Metadata", "RefreshMetadata": "Obnovit Metadata",
"ReplaceExistingImages": "Nahradit existuj\u00edc\u00ed obr\u00e1zky", "ReplaceExistingImages": "Nahradit existuj\u00edc\u00ed obr\u00e1zky",
"ReplaceAllMetadata": "Replace all metadata", "ReplaceAllMetadata": "P\u0159epsat v\u0161echna metadata",
"SearchForMissingMetadata": "Search for missing metadata", "SearchForMissingMetadata": "Hled\u00e1n\u00ed chyb\u011bj\u00edc\u00edch metadat",
"LabelRefreshMode": "Refresh mode:", "LabelRefreshMode": "M\u00f3d obnovy:",
"NoItemsFound": "Nenalezeny \u017e\u00e1dn\u00e9 polo\u017eky.", "NoItemsFound": "Nenalezeny \u017e\u00e1dn\u00e9 polo\u017eky.",
"HeaderSaySomethingLike": "Vyslovte n\u011bco jako...", "HeaderSaySomethingLike": "Vyslovte n\u011bco jako...",
"ButtonTryAgain": "Zkusit znovu", "ButtonTryAgain": "Zkusit znovu",
@ -110,35 +110,35 @@
"Favorite": "Obl\u00edben\u00e9", "Favorite": "Obl\u00edben\u00e9",
"Like": "M\u00e1m r\u00e1d", "Like": "M\u00e1m r\u00e1d",
"Dislike": "Nem\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", "Open": "Otev\u0159\u00edt",
"Play": "P\u0159ehr\u00e1t", "Play": "P\u0159ehr\u00e1t",
"Queue": "Fronta", "Queue": "Fronta",
"Shuffle": "N\u00e1hodn\u011b", "Shuffle": "N\u00e1hodn\u011b",
"Identify": "Identifikuj", "Identify": "Identifikuj",
"EditImages": "Editace obr\u00e1zk\u016f", "EditImages": "Editace obr\u00e1zk\u016f",
"EditInfo": "Edit info", "EditInfo": "Editace info",
"Sync": "Sync", "Sync": "Synchronizace",
"InstantMix": "Okam\u017eit\u00e9 m\u00edch\u00e1n\u00ed", "InstantMix": "Okam\u017eit\u00e9 m\u00edch\u00e1n\u00ed",
"ViewAlbum": "Zobrazit album", "ViewAlbum": "Zobrazit album",
"ViewArtist": "Zobrazit \u00fam\u011blce", "ViewArtist": "Zobrazit \u00fam\u011blce",
"QueueAllFromHere": "Za\u0159adit v\u0161e do fronty", "QueueAllFromHere": "Za\u0159adit v\u0161e do fronty",
"PlayAllFromHere": "P\u0159ehr\u00e1t v\u0161e odsud", "PlayAllFromHere": "P\u0159ehr\u00e1t v\u0161e odsud",
"PlayFromBeginning": "Play from beginning", "PlayFromBeginning": "P\u0159ehr\u00e1t od za\u010d\u00e1tku",
"ResumeAt": "Resume from {0}", "ResumeAt": "Obnovit p\u0159ehr\u00e1v\u00e1n\u00ed od {0}",
"RemoveFromPlaylist": "Odebrat z playlistu", "RemoveFromPlaylist": "Odebrat z playlistu",
"RemoveFromCollection": "Remove from collection", "RemoveFromCollection": "Odebrat z kolekce",
"Trailer": "Uk\u00e1zka\/trailer", "Trailer": "Uk\u00e1zka\/trailer",
"MarkPlayed": "Ozna\u010dit p\u0159ehran\u00e9", "MarkPlayed": "Ozna\u010dit p\u0159ehran\u00e9",
"MarkUnplayed": "Ozna\u010dit nep\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.", "PleaseSelectTwoItems": "Vyberte nejm\u00e9n\u011b dv\u011b polo\u017eky pros\u00edm.",
"TryMultiSelect": "Vyzkou\u0161ej multi-v\u00fdb\u011br", "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!", "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", "HeaderConfirmRecordingCancellation": "Potvrzen\u00ed zru\u0161en\u00ed nahr\u00e1v\u00e1n\u00ed",
"MessageConfirmRecordingCancellation": "Jste si jisti, \u017ee chcete zru\u0161it tuto nahr\u00e1vku?", "MessageConfirmRecordingCancellation": "Jste si jisti, \u017ee chcete zru\u0161it tuto nahr\u00e1vku?",
"Error": "Chyba", "Error": "Chyba",
"VoiceInput": "Voice Input", "VoiceInput": "Hlasov\u00fd vstup",
"LabelContentType": "Typ obsahu:", "LabelContentType": "Typ obsahu:",
"LabelPath": "Cesta k souboru:", "LabelPath": "Cesta k souboru:",
"LabelTitle": "N\u00e1zev:", "LabelTitle": "N\u00e1zev:",
@ -183,16 +183,16 @@
"LabelAirsAfterSeason": "Vys\u00edl\u00e1no po sez\u00f3n\u011b:", "LabelAirsAfterSeason": "Vys\u00edl\u00e1no po sez\u00f3n\u011b:",
"LabelAirsBeforeEpisode": "Vys\u00edl\u00e1no p\u0159ed epizodou:", "LabelAirsBeforeEpisode": "Vys\u00edl\u00e1no p\u0159ed epizodou:",
"HeaderExternalIds": "Extern\u00ed Id:", "HeaderExternalIds": "Extern\u00ed Id:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Nastaven\u00ed zobrazen\u00ed",
"LabelTreatImageAs": "Pova\u017eovat obr\u00e1zek za:", "LabelTreatImageAs": "Pova\u017eovat obr\u00e1zek za:",
"LabelDisplayOrder": "Po\u0159ad\u00ed zobrazen\u00ed:", "LabelDisplayOrder": "Po\u0159ad\u00ed zobrazen\u00ed:",
"Countries": "Countries", "Countries": "Zem\u011b",
"Genres": "Genres", "Genres": "\u017d\u00e1nry",
"HeaderPlotKeywords": "Kl\u00ed\u010dov\u00e1 slova obsahu", "HeaderPlotKeywords": "Kl\u00ed\u010dov\u00e1 slova obsahu",
"Studios": "Studios", "Studios": "Studia",
"Tags": "Tagy", "Tags": "Tagy",
"HeaderMetadataSettings": "Nastaven\u00ed metadat", "HeaderMetadataSettings": "Nastaven\u00ed metadat",
"People": "People", "People": "Lid\u00e9",
"LabelMetadataDownloadLanguage": "Preferovan\u00fd jazyk:", "LabelMetadataDownloadLanguage": "Preferovan\u00fd jazyk:",
"LabelLockItemToPreventChanges": "Uzamknout polo\u017eku pro z\u00e1branu budouc\u00edch zm\u011bn", "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.", "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:", "LabelBirthDate": "Datum narozen\u00ed:",
"LabelDeathDate": "Datum \u00famrt\u00ed:", "LabelDeathDate": "Datum \u00famrt\u00ed:",
"LabelEndDate": "Datum ukon\u010den\u00ed:", "LabelEndDate": "Datum ukon\u010den\u00ed:",
"LabelSeasonNumber": "Season number:", "LabelSeasonNumber": "\u010c\u00edslo sez\u00f3ny:",
"LabelEpisodeNumber": "Episode number:", "LabelEpisodeNumber": "\u010c\u00edslo epizody:",
"LabelTrackNumber": "\u010c\u00edslo stopy:", "LabelTrackNumber": "\u010c\u00edslo stopy:",
"LabelNumber": "\u010c\u00edslo:", "LabelNumber": "\u010c\u00edslo:",
"LabelDiscNumber": "\u010c\u00edslo disku", "LabelDiscNumber": "\u010c\u00edslo disku",
"LabelParentNumber": "\u010c\u00edslo p\u0159edch\u016fdce", "LabelParentNumber": "\u010c\u00edslo p\u0159edch\u016fdce",
"SortName": "Set\u0159\u00eddit dle n\u00e1zvu", "SortName": "Set\u0159\u00eddit dle n\u00e1zvu",
"ReleaseDate": "Release date", "ReleaseDate": "Datum vyd\u00e1n\u00ed",
"Continuing": "Pokra\u010dov\u00e1n\u00ed", "Continuing": "Pokra\u010dov\u00e1n\u00ed",
"Ended": "Ukon\u010deno", "Ended": "Ukon\u010deno",
"HeaderEnabledFields": "Povolen\u00e9 pole", "HeaderEnabledFields": "Povolen\u00e9 pole",
@ -217,26 +217,26 @@
"Backdrops": "Pozad\u00ed", "Backdrops": "Pozad\u00ed",
"Images": "Obr\u00e1zky", "Images": "Obr\u00e1zky",
"Keywords": "Kl\u00ed\u010dov\u00e1 slova", "Keywords": "Kl\u00ed\u010dov\u00e1 slova",
"Runtime": "Runtime", "Runtime": "D\u00e9lka",
"ProductionLocations": "Production locations", "ProductionLocations": "M\u00edsto v\u00fdroby",
"BirthLocation": "Birth location", "BirthLocation": "M\u00edsto narozen\u00ed",
"ParentalRating": "Rodi\u010dovsk\u00e9 hodnocen\u00ed", "ParentalRating": "Rodi\u010dovsk\u00e9 hodnocen\u00ed",
"Name": "Name", "Name": "N\u00e1zev",
"Overview": "Overview", "Overview": "P\u0159ehled\/Obsah",
"LabelType": "Typ:", "LabelType": "Typ:",
"LabelPersonRole": "Role:", "LabelPersonRole": "Role:",
"LabelPersonRoleHelp": "Example: Ice cream truck driver", "LabelPersonRoleHelp": "P\u0159\u00edklad: \u0158idi\u010d kami\u00f3nu se zmrzlinou",
"Actor": "Herec", "Actor": "Herec",
"Composer": "Skladatel", "Composer": "Skladatel",
"Director": "Re\u017eis\u00e9r", "Director": "Re\u017eis\u00e9r",
"GuestStar": "Guest star", "GuestStar": "Hostuj\u00edc\u00ed hv\u011bzda",
"Producer": "Producent", "Producer": "Producent",
"Writer": "Napsal", "Writer": "Napsal",
"InstallingPackage": "Instalace {0}", "InstallingPackage": "Instalace {0}",
"PackageInstallCompleted": "Instalace {0} dokon\u010dena.", "PackageInstallCompleted": "Instalace {0} dokon\u010dena.",
"PackageInstallFailed": "Instalace {0} selhala!!!", "PackageInstallFailed": "Instalace {0} selhala!!!",
"PackageInstallCancelled": "Instalace {0} zru\u0161ena.", "PackageInstallCancelled": "Instalace {0} zru\u0161ena.",
"SeriesYearToPresent": "{0}-Sou\u010dasnost", "SeriesYearToPresent": "{0} - Sou\u010dasnost",
"ValueOneSong": "1 song", "ValueOneSong": "1 song",
"ValueSongCount": "{0} song\u016f", "ValueSongCount": "{0} song\u016f",
"ValueOneMovie": "1 film", "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.", "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.", "PleaseEnterNameOrId": "Pros\u00edm, zadejte n\u00e1zev nebo extern\u00ed Id.",
"MessageItemSaved": "Polo\u017eka ulo\u017eena.", "MessageItemSaved": "Polo\u017eka ulo\u017eena.",
"SearchResults": "Search Results", "SearchResults": "V\u00fdsledky vyhled\u00e1v\u00e1n\u00ed",
"SyncToOtherDevice": "Sync to other device", "SyncToOtherDevice": "Synchronizovat na dal\u0161\u00ed za\u0159\u00edzen\u00ed",
"MakeAvailableOffline": "Make available offline", "MakeAvailableOffline": "Zp\u0159\u00edstupnit offline",
"ServerNameIsRestarting": "Emby Server - {0} is restarting.", "ServerNameIsRestarting": "Emby Server - {0} je restartov\u00e1n.",
"ServerNameIsShuttingDown": "Emby Server - {0} is shutting down.", "ServerNameIsShuttingDown": "Emby Server - {0} je vyp\u00edn\u00e1n.",
"HeaderDeleteItems": "Odstranit polo\u017eky", "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?", "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", "SyncJobCreated": "\u00daloha Sync vytvo\u0159ena",
"LabelSyncTo": "Sync do:", "LabelSyncTo": "Sync do:",
"LabelSyncJobName": "N\u00e1zev Sync \u00falohy:", "LabelSyncJobName": "N\u00e1zev Sync \u00falohy:",
"LabelQuality": "Kvalita:", "LabelQuality": "Kvalita:",
"LabelSyncNoTargetsHelp": "Vypad\u00e1 to, \u017ee v sou\u010dasn\u00e9 dob\u011b nem\u00e1te \u017e\u00e1dn\u00e9 aplikace, kter\u00e9 podporuj\u00ed synchronizaci.", "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", "LearnMore": "Zjistit v\u00edce",
"LabelProfile": "Profil:", "LabelProfile": "Profil:",
"LabelBitrateMbps": "Datov\u00fd tok (Mbps):", "LabelBitrateMbps": "Datov\u00fd tok (Mbps):",
@ -279,76 +279,80 @@
"LabelItemLimit": "Limit polo\u017eek:", "LabelItemLimit": "Limit polo\u017eek:",
"LabelItemLimitHelp": "Voliteln\u00e9. Nastaven\u00ed limitu k po\u010dtu polo\u017eek, kter\u00e9 budou synchronizovan\u00e9.", "LabelItemLimitHelp": "Voliteln\u00e9. Nastaven\u00ed limitu k po\u010dtu polo\u017eek, kter\u00e9 budou synchronizovan\u00e9.",
"PleaseSelectDeviceToSyncTo": "Vyberte za\u0159\u00edzen\u00ed k synchronizaci.", "PleaseSelectDeviceToSyncTo": "Vyberte za\u0159\u00edzen\u00ed k synchronizaci.",
"Screenshots": "Screenshots", "Screenshots": "Sn\u00edmky obrazovky",
"MoveRight": "Move right", "MoveRight": "Posunout vpravo",
"MoveLeft": "Move left", "MoveLeft": "Posunout vlevo",
"ConfirmDeleteImage": "Delete image?", "ConfirmDeleteImage": "Odstranit obr\u00e1zek?",
"HeaderEditImages": "Edit Images", "HeaderEditImages": "Editace obr\u00e1zk\u016f",
"Settings": "Nastaven\u00ed", "Settings": "Nastaven\u00ed",
"ShowIndicatorsFor": "Show indicators for:", "ShowIndicatorsFor": "Zobrazit indik\u00e1tor pro:",
"NewEpisodes": "New episodes", "NewEpisodes": "Nov\u00e9 episody",
"HDPrograms": "HD programs", "HDPrograms": "HD programy",
"LiveBroadcasts": "Live broadcasts", "LiveBroadcasts": "P\u0159\u00edm\u00e9 p\u0159enosy",
"Premieres": "Premieres", "Premieres": "Premi\u00e9ry",
"RepeatEpisodes": "Repeat episodes", "RepeatEpisodes": "Opakovan\u00ed epizod",
"DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.", "DvrSubscriptionRequired": "Emby DVR vy\u017eaduje aktivn\u00ed p\u0159edplatn\u00e9 Emby Premiere.",
"HeaderCancelRecording": "Cancel Recording", "HeaderCancelRecording": "Zru\u0161it nahr\u00e1v\u00e1n\u00ed",
"CancelRecording": "Cancel recording", "CancelRecording": "Zru\u0161it nahr\u00e1v\u00e1n\u00ed",
"HeaderKeepRecording": "Keep Recording", "HeaderKeepRecording": "Udr\u017eet nahr\u00e1v\u00e1n\u00ed",
"HeaderCancelSeries": "Cancel Series", "HeaderCancelSeries": "Ukon\u010dit Seri\u00e1l",
"HeaderKeepSeries": "Keep Series", "HeaderKeepSeries": "Udr\u017eet seri\u00e1l",
"HeaderLearnMore": "Learn More", "HeaderLearnMore": "Zjistit v\u00edce",
"DeleteMedia": "Delete media", "DeleteMedia": "Odstranit m\u00e9dia",
"SeriesSettings": "Series settings", "SeriesSettings": "Nastaven\u00ed seri\u00e1lu",
"HeaderRecordingOptions": "Recording Options", "HeaderRecordingOptions": "Nastaven\u00ed nahr\u00e1v\u00e1n\u00ed",
"CancelSeries": "Cancel series", "CancelSeries": "Ukon\u010dit Seri\u00e1l",
"DoNotRecord": "Do not record", "DoNotRecord": "Nenahr\u00e1vat",
"HeaderSeriesOptions": "Series Options", "HeaderSeriesOptions": "Nastaven\u00ed seri\u00e1lu",
"LabelChannels": "Channels:", "LabelChannels": "Kan\u00e1ly:",
"ChannelNameOnly": "Channel {0} only", "ChannelNameOnly": "Kan\u00e1l {0} jen",
"Anytime": "Anytime", "Anytime": "Kdykoliv",
"AroundTime": "Around {0}", "AroundTime": "Okolo {0}",
"LabelAirtime": "Airtime:", "LabelAirtime": "\u010cas vys\u00edl\u00e1n\u00ed:",
"AllChannels": "All channels", "AllChannels": "V\u0161echny kan\u00e1ly",
"LabelRecord": "Record:", "LabelRecord": "Z\u00e1znam:",
"NewEpisodesOnly": "New episodes only", "NewEpisodesOnly": "Jen nov\u00e9 epizody",
"AllEpisodes": "All episodes", "AllEpisodes": "V\u0161echny epizody",
"LabelStartWhenPossible": "Start when possible:", "LabelStartWhenPossible": "Za\u010d\u00edt jakmile je to mo\u017en\u00e9:",
"LabelStopWhenPossible": "Stop when possible:", "LabelStopWhenPossible": "Zastavit jakmile je to mo\u017en\u00e9:",
"MinutesBefore": "minutes before", "MinutesBefore": "minut p\u0159edem",
"MinutesAfter": "minutes after", "MinutesAfter": "minut po",
"SkipEpisodesAlreadyInMyLibrary": "Skip episodes that are already in my library", "SkipEpisodesAlreadyInMyLibrary": "P\u0159esko\u010dit epizody, kter\u00e9 jsou u\u017e v m\u00e9 knihovn\u011b",
"SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", "SkipEpisodesAlreadyInMyLibraryHelp": "Epizody budou porovn\u00e1v\u00e1ny s pou\u017eit\u00edm obdob\u00ed a \u010d\u00edsla epizody, pokud jsou k dispozici.",
"LabelKeepUpTo": "Keep up to:", "LabelKeepUpTo": "Aktualizovat k:",
"AsManyAsPossible": "As many as possible", "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.", "DefaultErrorMessage": "Do\u0161lo k chyb\u011b p\u0159i zpracov\u00e1n\u00ed po\u017eadavku. Pros\u00edm zkuste to znovu pozd\u011bji.",
"LabelKeep:": "Keep:", "LabelKeep:": "Udr\u017eet:",
"UntilIDelete": "Until I delete", "UntilIDelete": "Dokud nesma\u017eu",
"UntilSpaceNeeded": "Until space needed", "UntilSpaceNeeded": "Do pot\u0159ebn\u00e9ho prostoru",
"Categories": "Categories", "Categories": "Kategorie",
"Sports": "Sports", "Sports": "Sport",
"News": "News", "News": "Zpravodajstv\u00ed",
"Movies": "Movies", "Movies": "Filmy",
"Kids": "Kids", "Kids": "D\u011btsk\u00e9",
"EnableColorCodedBackgrounds": "Enable color coded backgrounds", "EnableColorCodedBackgrounds": "Aktivovat barevn\u011b ozna\u010den\u00e9 pozad\u00ed",
"SortChannelsBy": "Sort channels by:", "SortChannelsBy": "T\u0159\u00eddit kan\u00e1ly dle:",
"RecentlyWatched": "Recently watched", "RecentlyWatched": "Ned\u00e1vno shl\u00e9dnut\u00e9",
"ChannelNumber": "Channel number", "ChannelNumber": "\u010c\u00edslo kan\u00e1lu",
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere", "HeaderBenefitsEmbyPremiere": "V\u00fdhody Emby Premiere",
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", "ThankYouForTryingEnjoyOneMinute": "Pros\u00edm u\u017eijte si jednu minutu p\u0159ehr\u00e1v\u00e1n\u00ed. D\u011bkujeme v\u00e1m za vyzkou\u0161en\u00ed Emby.",
"HeaderTryPlayback": "Try Playback", "HeaderTryPlayback": "Zkusit playback",
"HowDidYouPay": "How did you pay?", "HowDidYouPay": "Jak chcete platit?",
"IHaveEmbyPremiere": "I have Emby Premiere", "IHaveEmbyPremiere": "Ji\u017e m\u00e1m Emby Premiere",
"IPurchasedThisApp": "I purchased this app", "IPurchasedThisApp": "Tuto aplikaci m\u00e1m ji\u017e zaplacenu",
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Obnovit n\u00e1kup",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Odemkn\u011bte pomoc\u00ed koup\u011b",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Odemknout {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"ButtonPlayOneMinute": "Play One Minute", "HeaderAlreadyPaid": "Already Paid?",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "ButtonPlayOneMinute": "P\u0159ehr\u00e1t jednu minutu",
"HeaderUnlockFeature": "Unlock Feature", "PlaceFavoriteChannelsAtBeginning": "Um\u00edstit obl\u00edben\u00e9 kan\u00e1ly na za\u010d\u00e1tek",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "HeaderUnlockFeature": "Odemknout funkci",
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.", "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?",
"HeaderPlayMyMedia": "Play my Media", "MessageDidYouKnowCinemaMode2": "S re\u017eimem Kino budou p\u0159ed hlavn\u00edm programem p\u0159ehr\u00e1ny upout\u00e1vky a u\u017eivatelsk\u00e1 intra.",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderPlayMyMedia": "P\u0159ehr\u00e1t moje M\u00e9dia",
"HeaderDiscoverEmbyPremiere": "Objevte v\u00fdhody Emby Premiere",
"OneChannel": "Jeden kan\u00e1l",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Ausstrahlungen vor Staffel:", "LabelAirsBeforeSeason": "Ausstrahlungen vor Staffel:",
"LabelAirsAfterSeason": "Ausstrahlungen nach Staffel:", "LabelAirsAfterSeason": "Ausstrahlungen nach Staffel:",
"LabelAirsBeforeEpisode": "Ausstrahlungen vor Episode:", "LabelAirsBeforeEpisode": "Ausstrahlungen vor Episode:",
"HeaderExternalIds": "Externe Id's:", "HeaderExternalIds": "Externe IDs:",
"HeaderDisplaySettings": "Anzeige Einstellungen", "HeaderDisplaySettings": "Anzeige Einstellungen",
"LabelTreatImageAs": "Bild behandeln, wie:", "LabelTreatImageAs": "Bild behandeln, wie:",
"LabelDisplayOrder": "Anzeigereihenfolge:", "LabelDisplayOrder": "Anzeigereihenfolge:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Kauf wiederherstellen", "ButtonRestorePreviousPurchase": "Kauf wiederherstellen",
"ButtonUnlockWithPurchase": "Freischalten durch Kauf", "ButtonUnlockWithPurchase": "Freischalten durch Kauf",
"ButtonUnlockPrice": "{0} freischalten", "ButtonUnlockPrice": "{0} freischalten",
"ButtonAlreadyPaid": "Schon bezahlt?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monatlich {0}",
"HeaderAlreadyPaid": "Schon bezahlt?",
"ButtonPlayOneMinute": "Eine Minute wiedergeben", "ButtonPlayOneMinute": "Eine Minute wiedergeben",
"PlaceFavoriteChannelsAtBeginning": "Platziere favorisierte Kan\u00e4le am Anfang", "PlaceFavoriteChannelsAtBeginning": "Platziere favorisierte Kan\u00e4le am Anfang",
"HeaderUnlockFeature": "Feature freischalten", "HeaderUnlockFeature": "Feature freischalten",
"MessageDidYouKnowCinemaMode": "Wusstest du schon, das du mit Emby Premiere dein Erlebnis mit Funktionen wie dem Kino-Modus noch verbessern kannst?", "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.", "MessageDidYouKnowCinemaMode2": "Der Kino-Modus bringt das richtige Kino-Erlebnis nach Hause, mit Trailern und eigenen Intros vor deinem Hauptfilm.",
"HeaderPlayMyMedia": "Spiele meine Medien ab", "HeaderPlayMyMedia": "Spiele meine Medien ab",
"HeaderDiscoverEmbyPremiere": "Entdecke Emby Premiere" "HeaderDiscoverEmbyPremiere": "Entdecke Emby Premiere",
"OneChannel": "Ein Kanal",
"ConfirmRemoveDownload": "Download entfernen?",
"AddedOnValue": "Hinzugef\u00fcgt {0}"
} }

View file

@ -1,46 +1,46 @@
{ {
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or 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": "Unlock this feature with an active Emby Premiere subscription.", "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.", "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}", "ValueSpecialEpisodeName": "Special - {0}",
"Share": "Share", "Share": "Share",
"Add": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5", "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}", "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.", "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", "Premiere": "Premiere",
"Live": "Live", "Live": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ac",
"Repeat": "Repeat", "Repeat": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7",
"TrackCount": "{0} tracks", "TrackCount": "{0} tracks",
"ItemCount": "{0} items", "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}", "OriginalAirDateValue": "Original air date: {0}",
"EndsAtValue": "Ends at {0}", "EndsAtValue": "Ends at {0}",
"OptionSundayShort": "Sun", "OptionSundayShort": "\u039a\u03c5\u03c1",
"OptionMondayShort": "Mon", "OptionMondayShort": "\u0394\u03b5\u03c5",
"OptionTuesdayShort": "Tue", "OptionTuesdayShort": "\u03a4\u03c1\u03b9",
"OptionWednesdayShort": "Wed", "OptionWednesdayShort": "\u03a4\u03b5\u03c4",
"OptionThursdayShort": "Thu", "OptionThursdayShort": "\u03a0\u03b5\u03bc",
"OptionFridayShort": "Fri", "OptionFridayShort": "\u03a0\u03b1\u03c1",
"OptionSaturdayShort": "Sat", "OptionSaturdayShort": "\u03a3\u03b1\u03b2",
"HeaderSelectDate": "Select Date", "HeaderSelectDate": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1\u03c2",
"ButtonOk": "Ok", "ButtonOk": "Ok",
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ", "ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
"ButtonGotIt": "Got It", "ButtonGotIt": "Got It",
"ButtonRestart": "Restart", "ButtonRestart": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
"RecordingCancelled": "Recording cancelled.", "RecordingCancelled": "Recording cancelled.",
"SeriesCancelled": "Series cancelled.", "SeriesCancelled": "Series cancelled.",
"RecordingScheduled": "Recording scheduled.", "RecordingScheduled": "Recording scheduled.",
"SeriesRecordingScheduled": "Series recording scheduled.", "SeriesRecordingScheduled": "Series recording scheduled.",
"HeaderNewRecording": "New Recording", "HeaderNewRecording": "\u039d\u03ad\u03b1 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae",
"Sunday": "Sunday", "Sunday": "\u039a\u03c5\u03c1\u03b9\u03b1\u03ba\u03ae",
"Monday": "Monday", "Monday": "\u0394\u03b5\u03c5\u03c4\u03ad\u03c1\u03b1",
"Tuesday": "Tuesday", "Tuesday": "\u03a4\u03c1\u03af\u03c4\u03b7",
"Wednesday": "Wednesday", "Wednesday": "\u03a4\u03b5\u03c4\u03ac\u03c1\u03c4\u03b7",
"Thursday": "Thursday", "Thursday": "\u03a0\u03ad\u03bc\u03c0\u03c4\u03b7",
"Friday": "Friday", "Friday": "\u03a0\u03b1\u03c1\u03b1\u03c3\u03ba\u03b5\u03c5\u03ae",
"Saturday": "Saturday", "Saturday": "\u03a3\u03ac\u03b2\u03b2\u03b1\u03c4\u03bf",
"Days": "Days", "Days": "\u0397\u03bc\u03ad\u03c1\u03b5\u03c2",
"RecordSeries": "Record series", "RecordSeries": "Record series",
"HeaderCinemaMode": "Cinema Mode", "HeaderCinemaMode": "Cinema Mode",
"HeaderCloudSync": "Cloud Sync", "HeaderCloudSync": "Cloud Sync",
@ -50,52 +50,52 @@
"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 personalize your media images.",
"CoverArt": "Cover Art", "CoverArt": "Cover Art",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", "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.", "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.", "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.", "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.", "FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.",
"HeaderConvertYourRecordings": "Convert Your Recordings", "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", "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", "Download": "Download",
"Advanced": "Advanced", "Advanced": "Advanced",
"Delete": "Delete", "Delete": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae",
"HeaderDeleteItem": "Delete Item", "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?", "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.", "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", "HeaderAddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"NewCollection": "New Collection", "NewCollection": "\u039d\u03ad\u03b1 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"LabelCollection": "Collection:", "LabelCollection": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae:",
"Help": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1", "Help": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1",
"NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.", "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", "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:", "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\"", "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.", "MessageItemsAdded": "Items added.",
"OptionNew": "New...", "OptionNew": "\u039d\u03ad\u03bf...",
"LabelPlaylist": "Playlist:", "LabelPlaylist": "\u039b\u03af\u03c3\u03c4\u03b1:",
"AddToPlaylist": "Add to playlist", "AddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u03bb\u03af\u03c3\u03c4\u03b1",
"HeaderAddToPlaylist": "Add to Playlist", "HeaderAddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u039b\u03af\u03c3\u03c4\u03b1",
"Subtitles": "Subtitles", "Subtitles": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9",
"SearchForSubtitles": "Search for Subtitles", "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", "LabelLanguage": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1",
"Search": "Search", "Search": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7",
"NoSubtitleSearchResultsFound": "No results found.", "NoSubtitleSearchResultsFound": "No results found.",
"File": "File", "File": "File",
"MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
"ConfirmDeletion": "Confirm Deletion", "ConfirmDeletion": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03af\u03c9\u03c3\u03b7 \u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2",
"MySubtitles": "My Subtitles", "MySubtitles": "\u039f\u03b9 \u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03bc\u03bf\u03c5",
"MessageDownloadQueued": "Download queued.", "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", "UnlockGuide": "Unlock Guide",
"RefreshMetadata": "Refresh Metadata", "RefreshMetadata": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7 \u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd",
"ReplaceExistingImages": "Replace existing images", "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", "ReplaceAllMetadata": "Replace all metadata",
"SearchForMissingMetadata": "Search for missing metadata", "SearchForMissingMetadata": "Search for missing metadata",
"LabelRefreshMode": "Refresh mode:", "LabelRefreshMode": "Refresh mode:",
@ -139,7 +139,7 @@
"MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?", "MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?",
"Error": "Error", "Error": "Error",
"VoiceInput": "Voice Input", "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:", "LabelPath": "Path:",
"LabelTitle": "Title:", "LabelTitle": "Title:",
"LabelOriginalTitle": "Original title:", "LabelOriginalTitle": "Original title:",
@ -147,7 +147,7 @@
"LabelDateAdded": "Date added:", "LabelDateAdded": "Date added:",
"ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings", "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:", "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 ;", "LabelArtistsHelp": "Separate multiple using ;",
"LabelAlbumArtists": "Album artists:", "LabelAlbumArtists": "Album artists:",
"LabelAlbum": "Album:", "LabelAlbum": "Album:",
@ -162,7 +162,7 @@
"LabelOverview": "Overview:", "LabelOverview": "Overview:",
"LabelShortOverview": "Short overview:", "LabelShortOverview": "Short overview:",
"LabelReleaseDate": "Release date:", "LabelReleaseDate": "Release date:",
"LabelYear": "Year:", "LabelYear": "\u0388\u03c4\u03bf\u03c2:",
"LabelPlaceOfBirth": "Place of birth:", "LabelPlaceOfBirth": "Place of birth:",
"LabelAirDays": "Air days:", "LabelAirDays": "Air days:",
"LabelAirTime": "Air time:", "LabelAirTime": "Air time:",
@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -196,7 +196,7 @@
"LabelMetadataDownloadLanguage": "Preferred download language:", "LabelMetadataDownloadLanguage": "Preferred download language:",
"LabelLockItemToPreventChanges": "Lock this item to prevent future changes", "LabelLockItemToPreventChanges": "Lock this item to prevent future changes",
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", "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:", "LabelDynamicExternalId": "{0} Id:",
"LabelBirthYear": "Birth year:", "LabelBirthYear": "Birth year:",
"LabelBirthDate": "Birth date:", "LabelBirthDate": "Birth date:",
@ -220,7 +220,7 @@
"Runtime": "Runtime", "Runtime": "Runtime",
"ProductionLocations": "Production locations", "ProductionLocations": "Production locations",
"BirthLocation": "Birth location", "BirthLocation": "Birth location",
"ParentalRating": "Parental Rating", "ParentalRating": "\u039a\u03b1\u03c4\u03b1\u03bb\u03bb\u03b7\u03bb\u03cc\u03c4\u03b7\u03c4\u03b1",
"Name": "Name", "Name": "Name",
"Overview": "Overview", "Overview": "Overview",
"LabelType": "Type:", "LabelType": "Type:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -47,7 +47,7 @@
"HeaderOfflineDownloads": "Offline Media", "HeaderOfflineDownloads": "Offline Media",
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", "HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.",
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", "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", "CoverArt": "Cover Art",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
"HeaderFreeApps": "Free Emby Apps", "HeaderFreeApps": "Free Emby Apps",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favourite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favourite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Transmisi\u00f3n antes de la temporada:", "LabelAirsBeforeSeason": "Transmisi\u00f3n antes de la temporada:",
"LabelAirsAfterSeason": "Transmisi\u00f3n despu\u00e9s de la temporada:", "LabelAirsAfterSeason": "Transmisi\u00f3n despu\u00e9s de la temporada:",
"LabelAirsBeforeEpisode": "Transmisi\u00f3n antes del episodio:", "LabelAirsBeforeEpisode": "Transmisi\u00f3n antes del episodio:",
"HeaderExternalIds": "Id\u00b4s Externos:", "HeaderExternalIds": "IDs Externos:",
"HeaderDisplaySettings": "Configuraci\u00f3n de Pantalla", "HeaderDisplaySettings": "Configuraci\u00f3n de Pantalla",
"LabelTreatImageAs": "Tratar imagen como:", "LabelTreatImageAs": "Tratar imagen como:",
"LabelDisplayOrder": "Orden para mostrar:", "LabelDisplayOrder": "Orden para mostrar:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restaurar Compra", "ButtonRestorePreviousPurchase": "Restaurar Compra",
"ButtonUnlockWithPurchase": "Desbloquear con una Compra", "ButtonUnlockWithPurchase": "Desbloquear con una Compra",
"ButtonUnlockPrice": "Desbloquear {0}", "ButtonUnlockPrice": "Desbloquear {0}",
"ButtonAlreadyPaid": "\u00bfYa esta pagado?", "EmbyPremiereMonthlyWithPrice": "Emby Premier Mensual {0}",
"HeaderAlreadyPaid": "\u00bfYa ha pagado?",
"ButtonPlayOneMinute": "Reproducir un minuto", "ButtonPlayOneMinute": "Reproducir un minuto",
"PlaceFavoriteChannelsAtBeginning": "Colocar canales favoritos al inicio", "PlaceFavoriteChannelsAtBeginning": "Colocar canales favoritos al inicio",
"HeaderUnlockFeature": "Desbloquear Caracter\u00edstica", "HeaderUnlockFeature": "Desbloquear Caracter\u00edstica",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "MessageDidYouKnowCinemaMode": "\u00bfSab\u00eda que con Emby Premier, puede mejorar su experiencia con caracter\u00edsticas como Modo Cine?",
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.", "MessageDidYouKnowCinemaMode2": "El Modo Cine le da una verdadera experiencia de cine con trailers e intros personalizados antes de la presentaci\u00f3n estelar.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Reproducir mis Medios",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Descubra Emby Premier",
"OneChannel": "Un canal",
"ConfirmRemoveDownload": "\u00bfEliminar descarga?",
"AddedOnValue": "Agregado {0}"
} }

View file

@ -29,7 +29,7 @@
"ButtonGotIt": "Lo tengo", "ButtonGotIt": "Lo tengo",
"ButtonRestart": "Reiniciar", "ButtonRestart": "Reiniciar",
"RecordingCancelled": "Grabaci\u00f3n cancelada.", "RecordingCancelled": "Grabaci\u00f3n cancelada.",
"SeriesCancelled": "Series cancelled.", "SeriesCancelled": "Series cancelada.",
"RecordingScheduled": "Grabaci\u00f3n programada.", "RecordingScheduled": "Grabaci\u00f3n programada.",
"SeriesRecordingScheduled": "Series recording scheduled.", "SeriesRecordingScheduled": "Series recording scheduled.",
"HeaderNewRecording": "Nueva grabaci\u00f3n", "HeaderNewRecording": "Nueva grabaci\u00f3n",
@ -117,8 +117,8 @@
"Shuffle": "Mezclar", "Shuffle": "Mezclar",
"Identify": "Identificar", "Identify": "Identificar",
"EditImages": "Editar im\u00e1genes", "EditImages": "Editar im\u00e1genes",
"EditInfo": "Edit info", "EditInfo": "Editar info",
"Sync": "Sync", "Sync": "Sincronizar",
"InstantMix": "Mix instant\u00e1neo", "InstantMix": "Mix instant\u00e1neo",
"ViewAlbum": "Ver album", "ViewAlbum": "Ver album",
"ViewArtist": "Ver artista", "ViewArtist": "Ver artista",
@ -141,8 +141,8 @@
"VoiceInput": "Voice Input", "VoiceInput": "Voice Input",
"LabelContentType": "Tipo de contenido:", "LabelContentType": "Tipo de contenido:",
"LabelPath": "Ruta:", "LabelPath": "Ruta:",
"LabelTitle": "Title:", "LabelTitle": "T\u00edtulo",
"LabelOriginalTitle": "Original title:", "LabelOriginalTitle": "T\u00edtulo original",
"LabelSortTitle": "Sort title:", "LabelSortTitle": "Sort title:",
"LabelDateAdded": "Fecha a\u00f1adido:", "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.", "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:", "LabelOverview": "Resumen:",
"LabelShortOverview": "Resumen corto:", "LabelShortOverview": "Resumen corto:",
"LabelReleaseDate": "Fecha de lanzamiento:", "LabelReleaseDate": "Fecha de lanzamiento:",
"LabelYear": "Year:", "LabelYear": "A\u00f1o:",
"LabelPlaceOfBirth": "Lugar de nacimiento:", "LabelPlaceOfBirth": "Lugar de nacimiento:",
"LabelAirDays": "D\u00edas de emisi\u00f3n:", "LabelAirDays": "D\u00edas de emisi\u00f3n:",
"LabelAirTime": "Tiempo de emisi\u00f3n:", "LabelAirTime": "Tiempo de emisi\u00f3n:",
@ -186,13 +186,13 @@
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Tratar imagen como:", "LabelTreatImageAs": "Tratar imagen como:",
"LabelDisplayOrder": "Mostrar orden:", "LabelDisplayOrder": "Mostrar orden:",
"Countries": "Countries", "Countries": "Pa\u00edses",
"Genres": "Genres", "Genres": "G\u00e9neros",
"HeaderPlotKeywords": "Palabras clave del reparto", "HeaderPlotKeywords": "Palabras clave del reparto",
"Studios": "Studios", "Studios": "Estudios",
"Tags": "Etiquetas", "Tags": "Etiquetas",
"HeaderMetadataSettings": "Ajustes de metadatos", "HeaderMetadataSettings": "Ajustes de metadatos",
"People": "People", "People": "Gente",
"LabelMetadataDownloadLanguage": "Idioma preferido visualizado", "LabelMetadataDownloadLanguage": "Idioma preferido visualizado",
"LabelLockItemToPreventChanges": "Bloquear este \u00edtem para evitar futuros cambios", "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.", "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", "LabelDiscNumber": "N\u00famero de disco",
"LabelParentNumber": "N\u00famero de los padres", "LabelParentNumber": "N\u00famero de los padres",
"SortName": "Ordenar por nombre", "SortName": "Ordenar por nombre",
"ReleaseDate": "Release date", "ReleaseDate": "Fecha de lanzamiento",
"Continuing": "Continuando", "Continuing": "Continuando",
"Ended": "Finalizado", "Ended": "Finalizado",
"HeaderEnabledFields": "Campos activados", "HeaderEnabledFields": "Campos activados",
@ -221,7 +221,7 @@
"ProductionLocations": "Production locations", "ProductionLocations": "Production locations",
"BirthLocation": "Birth location", "BirthLocation": "Birth location",
"ParentalRating": "Parental Rating", "ParentalRating": "Parental Rating",
"Name": "Name", "Name": "Nombre",
"Overview": "Overview", "Overview": "Overview",
"LabelType": "Tipo:", "LabelType": "Tipo:",
"LabelPersonRole": "Rol:", "LabelPersonRole": "Rol:",
@ -229,7 +229,7 @@
"Actor": "Actor", "Actor": "Actor",
"Composer": "Compositor", "Composer": "Compositor",
"Director": "Director", "Director": "Director",
"GuestStar": "Guest star", "GuestStar": "Estrella invitada",
"Producer": "Productor", "Producer": "Productor",
"Writer": "Escritor", "Writer": "Escritor",
"InstallingPackage": "Instalando {0}", "InstallingPackage": "Instalando {0}",
@ -279,11 +279,11 @@
"LabelItemLimit": "L\u00edmite de \u00edtems:", "LabelItemLimit": "L\u00edmite de \u00edtems:",
"LabelItemLimitHelp": "Opcional. Pon un l\u00edmite de cantidad de \u00edtems que se sincronizar\u00e1n.", "LabelItemLimitHelp": "Opcional. Pon un l\u00edmite de cantidad de \u00edtems que se sincronizar\u00e1n.",
"PleaseSelectDeviceToSyncTo": "Por favor selecciona el dispositivo donde quieres sincronizar.", "PleaseSelectDeviceToSyncTo": "Por favor selecciona el dispositivo donde quieres sincronizar.",
"Screenshots": "Screenshots", "Screenshots": "Capturas de pantalla",
"MoveRight": "Move right", "MoveRight": "Mover derecha",
"MoveLeft": "Move left", "MoveLeft": "Mover izquierda",
"ConfirmDeleteImage": "Delete image?", "ConfirmDeleteImage": "Borrar imagen",
"HeaderEditImages": "Edit Images", "HeaderEditImages": "Editar Im\u00e1genes",
"Settings": "Ajustes", "Settings": "Ajustes",
"ShowIndicatorsFor": "Show indicators for:", "ShowIndicatorsFor": "Show indicators for:",
"NewEpisodes": "New episodes", "NewEpisodes": "New episodes",
@ -295,7 +295,7 @@
"HeaderCancelRecording": "Cancel Recording", "HeaderCancelRecording": "Cancel Recording",
"CancelRecording": "Cancel recording", "CancelRecording": "Cancel recording",
"HeaderKeepRecording": "Keep Recording", "HeaderKeepRecording": "Keep Recording",
"HeaderCancelSeries": "Cancel Series", "HeaderCancelSeries": "Cancelar Series",
"HeaderKeepSeries": "Keep Series", "HeaderKeepSeries": "Keep Series",
"HeaderLearnMore": "Learn More", "HeaderLearnMore": "Learn More",
"DeleteMedia": "Delete media", "DeleteMedia": "Delete media",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"ButtonPlayOneMinute": "Play One Minute", "HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Reproducir un minuto",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -1,7 +1,7 @@
{ {
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.", "MessageUnlockAppWithPurchaseOrSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec un petit achat en une fois, ou avec une souscription Emby Premiere.",
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.", "MessageUnlockAppWithSupporter": "D\u00e9verrouillez cette fonctionnalit\u00e9 avec une souscription 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.", "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}", "ValueSpecialEpisodeName": "Sp\u00e9cial - {0}",
"Share": "Partager", "Share": "Partager",
"Add": "Ajouter", "Add": "Ajouter",
@ -29,7 +29,7 @@
"ButtonGotIt": "Vu", "ButtonGotIt": "Vu",
"ButtonRestart": "Red\u00e9marrer", "ButtonRestart": "Red\u00e9marrer",
"RecordingCancelled": "Enregistrement annul\u00e9.", "RecordingCancelled": "Enregistrement annul\u00e9.",
"SeriesCancelled": "Series cancelled.", "SeriesCancelled": "S\u00e9rie annul\u00e9e.",
"RecordingScheduled": "Enregistrement planifi\u00e9.", "RecordingScheduled": "Enregistrement planifi\u00e9.",
"SeriesRecordingScheduled": "Enregistrement de la s\u00e9rie pr\u00e9vue.", "SeriesRecordingScheduled": "Enregistrement de la s\u00e9rie pr\u00e9vue.",
"HeaderNewRecording": "Nouvel enregistrement", "HeaderNewRecording": "Nouvel enregistrement",
@ -42,22 +42,22 @@
"Saturday": "Samedi", "Saturday": "Samedi",
"Days": "Jours", "Days": "Jours",
"RecordSeries": "Enregistrer s\u00e9ries", "RecordSeries": "Enregistrer s\u00e9ries",
"HeaderCinemaMode": "Cinema Mode", "HeaderCinemaMode": "Mode Cin\u00e9ma",
"HeaderCloudSync": "Cloud Sync", "HeaderCloudSync": "Synchronisation avec le cloud",
"HeaderOfflineDownloads": "Offline Media", "HeaderOfflineDownloads": "Contenu multim\u00e9dia hors-ligne",
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", "HeaderOfflineDownloadsDescription": "T\u00e9l\u00e9chargez votre contenu multim\u00e9dia vers vos appareils pour une meilleure utilisation hors-ligne.",
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", "CloudSyncFeatureDescription": "Synchronisez votre contenu multim\u00e9dia vers le cloud pour le sauvegarder, l'archiver et le convertir plus facilement.",
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.", "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": "Cover Art", "CoverArt": "Pochette",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", "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": "Free Emby Apps", "HeaderFreeApps": "Apps Emby gratuites",
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", "FreeAppsFeatureDescription": "Profitez d'un acc\u00e8s gratuit \u00e0 certaines applications Emby pour vos appareils.",
"HeaderBecomeProjectSupporter": "Obtenez Emby Premiere", "HeaderBecomeProjectSupporter": "Obtenez Emby Premiere",
"MessageActiveSubscriptionRequiredSeriesRecordings": "Une souscription Emby Premiere active est n\u00e9cessaire pour cr\u00e9er des enregistrements automatiques de s\u00e9ries.", "MessageActiveSubscriptionRequiredSeriesRecordings": "Une souscription Emby Premiere active est n\u00e9cessaire pour cr\u00e9er des enregistrements automatiques de s\u00e9ries.",
"LabelEmailAddress": "E-mail address:", "LabelEmailAddress": "Adresse 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.", "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.", "FeatureRequiresEmbyPremiere": "Cette fonctionnalit\u00e9 requiert un compte Emby Premiere.",
"HeaderConvertYourRecordings": "Convert Your Recordings", "HeaderConvertYourRecordings": "Convertissez Vos Enregistrements",
"Record": "Enregistrer", "Record": "Enregistrer",
"Save": "Sauvegarder", "Save": "Sauvegarder",
"Edit": "Modifier", "Edit": "Modifier",
@ -236,13 +236,13 @@
"PackageInstallCompleted": "L'installation de {0} est termin\u00e9e.", "PackageInstallCompleted": "L'installation de {0} est termin\u00e9e.",
"PackageInstallFailed": "L'installation de {0} a \u00e9chou\u00e9.", "PackageInstallFailed": "L'installation de {0} a \u00e9chou\u00e9.",
"PackageInstallCancelled": "L'installation de {0} a \u00e9t\u00e9 annul\u00e9e.", "PackageInstallCancelled": "L'installation de {0} a \u00e9t\u00e9 annul\u00e9e.",
"SeriesYearToPresent": "{0}-Pr\u00e9sent", "SeriesYearToPresent": "{0} - Pr\u00e9sent",
"ValueOneSong": "1 chanson", "ValueOneSong": "1 chanson",
"ValueSongCount": "{0} chansons", "ValueSongCount": "{0} chansons",
"ValueOneMovie": "1 Film", "ValueOneMovie": "1 Film",
"ValueMovieCount": "{0} films", "ValueMovieCount": "{0} films",
"ValueOneSeries": "1 S\u00e9rie", "ValueOneSeries": "1 S\u00e9rie",
"ValueSeriesCount": "{0} series", "ValueSeriesCount": "{0} s\u00e9ries",
"ValueOneEpisode": "1 \u00e9pisode", "ValueOneEpisode": "1 \u00e9pisode",
"ValueEpisodeCount": "{0} \u00e9pisodes", "ValueEpisodeCount": "{0} \u00e9pisodes",
"ValueOneGame": "1 jeu", "ValueOneGame": "1 jeu",
@ -285,70 +285,74 @@
"ConfirmDeleteImage": "Supprimer l'image ?", "ConfirmDeleteImage": "Supprimer l'image ?",
"HeaderEditImages": "Modifier les images", "HeaderEditImages": "Modifier les images",
"Settings": "Param\u00e8tres", "Settings": "Param\u00e8tres",
"ShowIndicatorsFor": "Show indicators for:", "ShowIndicatorsFor": "Montrer les indicateurs pour:",
"NewEpisodes": "New episodes", "NewEpisodes": "Nouveaux \u00e9pisodes",
"HDPrograms": "HD programs", "HDPrograms": "Programmes HD",
"LiveBroadcasts": "Live broadcasts", "LiveBroadcasts": "Diffusions en direct",
"Premieres": "Premieres", "Premieres": "Premi\u00e8res",
"RepeatEpisodes": "Repeat episodes", "RepeatEpisodes": "R\u00e9p\u00e9ter les \u00e9pisodes",
"DvrSubscriptionRequired": "Emby DVR requires an active Emby Premiere subscription.", "DvrSubscriptionRequired": "Emby DVR n\u00e9cessite un abonnement \u00e0 Emby Premiere.",
"HeaderCancelRecording": "Cancel Recording", "HeaderCancelRecording": "Annuler l'enregistrement",
"CancelRecording": "Cancel recording", "CancelRecording": "Annuler l'enregistrement",
"HeaderKeepRecording": "Keep Recording", "HeaderKeepRecording": "Garder l'enregistrement",
"HeaderCancelSeries": "Cancel Series", "HeaderCancelSeries": "Annuler la s\u00e9rie",
"HeaderKeepSeries": "Keep Series", "HeaderKeepSeries": "Garder la s\u00e9rie",
"HeaderLearnMore": "Learn More", "HeaderLearnMore": "En savoir plus",
"DeleteMedia": "Delete media", "DeleteMedia": "Effacer cet objet",
"SeriesSettings": "Series settings", "SeriesSettings": "Configuration de la s\u00e9rie",
"HeaderRecordingOptions": "Recording Options", "HeaderRecordingOptions": "Options d'enregistrement",
"CancelSeries": "Cancel series", "CancelSeries": "Annuler la s\u00e9rie",
"DoNotRecord": "Do not record", "DoNotRecord": "Ne pas enregistrer",
"HeaderSeriesOptions": "Series Options", "HeaderSeriesOptions": "Options de la s\u00e9rie",
"LabelChannels": "Channels:", "LabelChannels": "Cha\u00eenes:",
"ChannelNameOnly": "Channel {0} only", "ChannelNameOnly": "Cha\u00eene {0} seulement",
"Anytime": "Anytime", "Anytime": "N'importe quand",
"AroundTime": "Around {0}", "AroundTime": "Vers {0}",
"LabelAirtime": "Airtime:", "LabelAirtime": "Temps d'antenne:",
"AllChannels": "All channels", "AllChannels": "Toutes les cha\u00eenes",
"LabelRecord": "Record:", "LabelRecord": "Enregistrer:",
"NewEpisodesOnly": "New episodes only", "NewEpisodesOnly": "Uniquement les nouveaux \u00e9pisodes",
"AllEpisodes": "All episodes", "AllEpisodes": "Tous les \u00e9pisodes",
"LabelStartWhenPossible": "Start when possible:", "LabelStartWhenPossible": "Commencer d\u00e8s que possible:",
"LabelStopWhenPossible": "Stop when possible:", "LabelStopWhenPossible": "Arr\u00eater d\u00e8s que possible:",
"MinutesBefore": "minutes before", "MinutesBefore": "minutes avant",
"MinutesAfter": "minutes after", "MinutesAfter": "minutes apr\u00e8s",
"SkipEpisodesAlreadyInMyLibrary": "Skip episodes that are already in my library", "SkipEpisodesAlreadyInMyLibrary": "Ne pas lire les \u00e9pisodes d\u00e9j\u00e0 pr\u00e9sents dans ma m\u00e9diath\u00e8que",
"SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", "SkipEpisodesAlreadyInMyLibraryHelp": "Les \u00e9pisodes seront compar\u00e9s selon leurs saisons et num\u00e9ros d'\u00e9pisodes, si possible.",
"LabelKeepUpTo": "Keep up to:", "LabelKeepUpTo": "Garder jusqu'\u00e0:",
"AsManyAsPossible": "As many as possible", "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.", "DefaultErrorMessage": "Il y a eu une erreur lors de l'ex\u00e9cution de la requ\u00eate. Veuillez r\u00e9essayer plus tard.",
"LabelKeep:": "Keep:", "LabelKeep:": "Garder:",
"UntilIDelete": "Until I delete", "UntilIDelete": "Jusqu'\u00e0 ce que je le supprime",
"UntilSpaceNeeded": "Until space needed", "UntilSpaceNeeded": "Jusqu'\u00e0 ce que l'espace disque est n\u00e9cessaire",
"Categories": "Categories", "Categories": "Cat\u00e9gories",
"Sports": "Sports", "Sports": "Sports",
"News": "News", "News": "Actualit\u00e9s",
"Movies": "Movies", "Movies": "Films",
"Kids": "Kids", "Kids": "Enfants",
"EnableColorCodedBackgrounds": "Enable color coded backgrounds", "EnableColorCodedBackgrounds": "Activer les arri\u00e8res-plans \u00e0 code-couleur",
"SortChannelsBy": "Sort channels by:", "SortChannelsBy": "Trier les cha\u00eenes par:",
"RecentlyWatched": "Recently watched", "RecentlyWatched": "Lus r\u00e9cemment",
"ChannelNumber": "Channel number", "ChannelNumber": "Num\u00e9ro de cha\u00eene",
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere", "HeaderBenefitsEmbyPremiere": "Avantages de Emby Premiere",
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", "ThankYouForTryingEnjoyOneMinute": "Profitez d'une minute de lecture. Merci d'avoir essay\u00e9 Emby.",
"HeaderTryPlayback": "Try Playback", "HeaderTryPlayback": "Essayer la lecture",
"HowDidYouPay": "How did you pay?", "HowDidYouPay": "Comment avez-vous pay\u00e9?",
"IHaveEmbyPremiere": "I have Emby Premiere", "IHaveEmbyPremiere": "J'ai Emby Premiere",
"IPurchasedThisApp": "I purchased this app", "IPurchasedThisApp": "J'ai achet\u00e9 cette application",
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restaurer l'achat",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "D\u00e9verrouillez par un achat.",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "D\u00e9verrouiller {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"ButtonPlayOneMinute": "Play One Minute", "HeaderAlreadyPaid": "Already Paid?",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "ButtonPlayOneMinute": "Lire une minute",
"HeaderUnlockFeature": "Unlock Feature", "PlaceFavoriteChannelsAtBeginning": "Mettre vos cha\u00eenes pr\u00e9f\u00e9r\u00e9es au d\u00e9but",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "HeaderUnlockFeature": "D\u00e9verrouiller la fonction",
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.", "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 ?",
"HeaderPlayMyMedia": "Play my Media", "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.",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderPlayMyMedia": "Lire mon contenu",
"HeaderDiscoverEmbyPremiere": "D\u00e9couvrez Emby Premiere",
"OneChannel": "Une cha\u00eene",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -1,7 +1,7 @@
{ {
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.", "MessageUnlockAppWithPurchaseOrSupporter": "Otklju\u010daj ovu mogu\u0107nost s malom jednokratnom kupnjom ili s aktivnom pretplatom Emby Premijere.",
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.", "MessageUnlockAppWithSupporter": "Otklju\u010daj ovu mogu\u0107nost sa pretplatom Emby Premijere.",
"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.", "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}", "ValueSpecialEpisodeName": "Specijal - {0}",
"Share": "Dijeli", "Share": "Dijeli",
"Add": "Dodaj", "Add": "Dodaj",
@ -42,19 +42,19 @@
"Saturday": "Subota", "Saturday": "Subota",
"Days": "Dani", "Days": "Dani",
"RecordSeries": "Snimi serije", "RecordSeries": "Snimi serije",
"HeaderCinemaMode": "Cinema Mode", "HeaderCinemaMode": "Kino na\u010din",
"HeaderCloudSync": "Cloud Sync", "HeaderCloudSync": "Sink. preko oblaka",
"HeaderOfflineDownloads": "Offline Media", "HeaderOfflineDownloads": "Izvanmre\u017eni mediji",
"HeaderOfflineDownloadsDescription": "Download media to your devices for easy offline use.", "HeaderOfflineDownloadsDescription": "Preuzimanje medija na svojim ure\u0111ajima za jednostavnu upotrebu izvan mre\u017ee.",
"CloudSyncFeatureDescription": "Sync your media to the cloud for easy backup, archiving, and converting.", "CloudSyncFeatureDescription": "Sinkronizirajte svoje medije na oblaku za jednostavni backup, arhiviranje i konvertiranje.",
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.", "CoverArtFeatureDescription": "\"Cover Art\" stvara zabavne naslovnice i druge tretmane koji \u0107e vam pomo\u0107i personalizirati va\u0161e medijske slike.",
"CoverArt": "Cover Art", "CoverArt": "Cover Art",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", "CinemaModeFeatureDescription": "Kino na\u010din vam daje pravi do\u017eivljaj kina s kratkim filmovima i prilago\u0111enim isje\u010dcima prije odabrane zna\u010dajke.",
"HeaderFreeApps": "Free Emby Apps", "HeaderFreeApps": "Besplatne Emby aplikacije",
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.", "FreeAppsFeatureDescription": "U\u017eivajte u slobodnom pristupu Emby aplikacija za svoje ure\u0111aje.",
"HeaderBecomeProjectSupporter": "Nabavite Emby Premijeru", "HeaderBecomeProjectSupporter": "Nabavite Emby Premijeru",
"MessageActiveSubscriptionRequiredSeriesRecordings": "Aktivna pretplata Emby Premijere je potrebna kako bi se napravilo automatsko snimanje serija.", "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.", "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.", "FeatureRequiresEmbyPremiere": "Ova zna\u010dajka zahtijeva aktivnu pretplatu Emby Premijere.",
"HeaderConvertYourRecordings": "Konvertiraj snimke", "HeaderConvertYourRecordings": "Konvertiraj snimke",
@ -236,7 +236,7 @@
"PackageInstallCompleted": "{0} instaliranje zavr\u0161eno.", "PackageInstallCompleted": "{0} instaliranje zavr\u0161eno.",
"PackageInstallFailed": "{0} instaliranje neuspjelo.", "PackageInstallFailed": "{0} instaliranje neuspjelo.",
"PackageInstallCancelled": "{0} instaliranje otkazano.", "PackageInstallCancelled": "{0} instaliranje otkazano.",
"SeriesYearToPresent": "{0}-sada", "SeriesYearToPresent": "{0} - sada",
"ValueOneSong": "1 pjesma", "ValueOneSong": "1 pjesma",
"ValueSongCount": "{0} pjesma", "ValueSongCount": "{0} pjesma",
"ValueOneMovie": "1 film", "ValueOneMovie": "1 film",
@ -334,21 +334,25 @@
"SortChannelsBy": "Slo\u017ei kanale po:", "SortChannelsBy": "Slo\u017ei kanale po:",
"RecentlyWatched": "Nedavno pogledano", "RecentlyWatched": "Nedavno pogledano",
"ChannelNumber": "Broj kanala", "ChannelNumber": "Broj kanala",
"HeaderBenefitsEmbyPremiere": "Benefits of Emby Premiere", "HeaderBenefitsEmbyPremiere": "Prednosti Emby premijere",
"ThankYouForTryingEnjoyOneMinute": "Please enjoy one minute of playback. Thank you for trying Emby.", "ThankYouForTryingEnjoyOneMinute": "Molimo Vas da u\u017eivate u jednoj minuti reprodukcije. Hvala \u0161to ste isprobali Emby.",
"HeaderTryPlayback": "Try Playback", "HeaderTryPlayback": "Isprobajte reprodukciju",
"HowDidYouPay": "How did you pay?", "HowDidYouPay": "Kako ste platili?",
"IHaveEmbyPremiere": "I have Emby Premiere", "IHaveEmbyPremiere": "Imam Emby Premijeru",
"IPurchasedThisApp": "I purchased this app", "IPurchasedThisApp": "Kupio sam ovu aplikaciju",
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Vrati kupovinu",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Otklju\u010daj s kupovinom",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Otklju\u010daj {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"ButtonPlayOneMinute": "Play One Minute", "HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Reproduciraj jednu minutu",
"PlaceFavoriteChannelsAtBeginning": "Postavi omiljene kanale na po\u010detak", "PlaceFavoriteChannelsAtBeginning": "Postavi omiljene kanale na po\u010detak",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Otklju\u010daj zna\u010dajke",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "MessageDidYouKnowCinemaMode": "Jeste li znali da s Emby Premijerom mo\u017eete pobolj\u0161ati svoje iskustvo sa zna\u010dajkama kao \u0161to su na\u010din kina?",
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.", "MessageDidYouKnowCinemaMode2": "Kino na\u010din vam daje pravi do\u017eivljaj kina s kratkim filmovima i prilago\u0111enim isje\u010dcima prije odabrane zna\u010dajke.",
"HeaderPlayMyMedia": "Play my Media", "HeaderPlayMyMedia": "Reproduciraj moje medije",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere" "HeaderDiscoverEmbyPremiere": "Otkrijte Emby Premijeru",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
} }

View file

@ -7,7 +7,7 @@
"Add": "Hozz\u00e1ad", "Add": "Hozz\u00e1ad",
"ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}", "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.", "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", "Premiere": "Premiere",
"Live": "Live", "Live": "Live",
"Repeat": "Ism\u00e9tl\u00e9s", "Repeat": "Ism\u00e9tl\u00e9s",
@ -15,7 +15,7 @@
"ItemCount": "{0} items", "ItemCount": "{0} items",
"ReleaseYearValue": "Release year: {0}", "ReleaseYearValue": "Release year: {0}",
"OriginalAirDateValue": "Original air date: {0}", "OriginalAirDateValue": "Original air date: {0}",
"EndsAtValue": "Ends at {0}", "EndsAtValue": "V\u00e1rhat\u00f3 befejez\u00e9s {0}",
"OptionSundayShort": "Sun", "OptionSundayShort": "Sun",
"OptionMondayShort": "Mon", "OptionMondayShort": "Mon",
"OptionTuesdayShort": "Tue", "OptionTuesdayShort": "Tue",
@ -32,7 +32,7 @@
"SeriesCancelled": "Series cancelled.", "SeriesCancelled": "Series cancelled.",
"RecordingScheduled": "Recording scheduled.", "RecordingScheduled": "Recording scheduled.",
"SeriesRecordingScheduled": "Series recording scheduled.", "SeriesRecordingScheduled": "Series recording scheduled.",
"HeaderNewRecording": "New Recording", "HeaderNewRecording": "\u00daj Felv\u00e9tel",
"Sunday": "Vas\u00e1rnap", "Sunday": "Vas\u00e1rnap",
"Monday": "H\u00e9tf\u0151", "Monday": "H\u00e9tf\u0151",
"Tuesday": "Kedd", "Tuesday": "Kedd",
@ -117,13 +117,13 @@
"Shuffle": "Kever\u00e9s", "Shuffle": "Kever\u00e9s",
"Identify": "Azonos\u00edt\u00e1s", "Identify": "Azonos\u00edt\u00e1s",
"EditImages": "K\u00e9pek szerkeszt\u00e9se", "EditImages": "K\u00e9pek szerkeszt\u00e9se",
"EditInfo": "Edit info", "EditInfo": "Adatok szerkeszt\u00e9se",
"Sync": "Sync", "Sync": "Sync",
"InstantMix": "Instant mix", "InstantMix": "Instant mix",
"ViewAlbum": "View album", "ViewAlbum": "View album",
"ViewArtist": "View artist", "ViewArtist": "View artist",
"QueueAllFromHere": "Queue all from here", "QueueAllFromHere": "Queue all from here",
"PlayAllFromHere": "Play all from here", "PlayAllFromHere": "\u00d6sszes vet\u00edt\u00e9se innen",
"PlayFromBeginning": "Play from beginning", "PlayFromBeginning": "Play from beginning",
"ResumeAt": "Resume from {0}", "ResumeAt": "Resume from {0}",
"RemoveFromPlaylist": "Remove from playlist", "RemoveFromPlaylist": "Remove from playlist",
@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:", "LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:", "LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:", "LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:", "HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings", "HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:", "LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:", "LabelDisplayOrder": "Display order:",
@ -286,7 +286,7 @@
"HeaderEditImages": "Edit Images", "HeaderEditImages": "Edit Images",
"Settings": "Be\u00e1ll\u00edt\u00e1sok", "Settings": "Be\u00e1ll\u00edt\u00e1sok",
"ShowIndicatorsFor": "Show indicators for:", "ShowIndicatorsFor": "Show indicators for:",
"NewEpisodes": "New episodes", "NewEpisodes": "\u00daj epiz\u00f3dok",
"HDPrograms": "HD programs", "HDPrograms": "HD programs",
"LiveBroadcasts": "Live broadcasts", "LiveBroadcasts": "Live broadcasts",
"Premieres": "Premieres", "Premieres": "Premieres",
@ -311,7 +311,7 @@
"LabelAirtime": "Airtime:", "LabelAirtime": "Airtime:",
"AllChannels": "All channels", "AllChannels": "All channels",
"LabelRecord": "Record:", "LabelRecord": "Record:",
"NewEpisodesOnly": "New episodes only", "NewEpisodesOnly": "Csak \u00faj epiz\u00f3dok",
"AllEpisodes": "All episodes", "AllEpisodes": "All episodes",
"LabelStartWhenPossible": "Start when possible:", "LabelStartWhenPossible": "Start when possible:",
"LabelStopWhenPossible": "Stop when possible:", "LabelStopWhenPossible": "Stop when possible:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase", "ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?", "EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute", "ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning", "PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature", "HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?", "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.", "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media", "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