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": {},
"ignore": [],
"version": "1.1.91",
"_release": "1.1.91",
"version": "1.1.105",
"_release": "1.1.105",
"_resolution": {
"type": "version",
"tag": "1.1.91",
"commit": "f94b80f14bce6922acf1dbd749a60ad54e4abfd8"
"tag": "1.1.105",
"commit": "d46515271d43d1b0f7dd19bb1834cfd457fb3326"
},
"_source": "https://github.com/MediaBrowser/Emby.ApiClient.Javascript.git",
"_target": "^1.1.51",

View File

@ -22,6 +22,27 @@
var self = this;
var webSocket;
var serverInfo = {};
var lastDetectedBitrate;
var lastDetectedBitrateTime;
var detectTimeout;
function redetectBitrate() {
stopBitrateDetection();
if (self.accessToken() && self.enableAutomaticBitrateDetection !== false) {
setTimeout(redetectBitrateInternal, 6000);
}
}
function redetectBitrateInternal() {
self.detectBitrate();
}
function stopBitrateDetection() {
if (detectTimeout) {
clearTimeout(detectTimeout);
}
}
/**
* Gets the server address.
@ -38,9 +59,14 @@
serverAddress = val;
lastDetectedBitrate = 0;
lastDetectedBitrateTime = 0;
if (changed) {
events.trigger(this, 'serveraddresschanged');
}
redetectBitrate();
}
return serverAddress;
@ -128,6 +154,7 @@
serverInfo.AccessToken = accessKey;
serverInfo.UserId = userId;
redetectBitrate();
};
self.encodeName = function (name) {
@ -239,7 +266,7 @@
resolve(response);
}, function (error) {
clearTimeout(timeout);
reject();
reject(error);
});
});
}
@ -421,11 +448,14 @@
}, function (error) {
console.log("Request failed to " + request.url);
// http://api.jquery.com/jQuery.ajax/
if (enableReconnection) {
if (error) {
console.log("Request failed to " + request.url + ' ' + error.toString());
} else {
console.log("Request timed out to " + request.url + ' ' + error.toString());
}
// http://api.jquery.com/jQuery.ajax/
if (!error && enableReconnection) {
console.log("Attempting reconnection");
var previousServerAddress = self.serverAddress();
@ -669,23 +699,67 @@
});
};
self.detectBitrate = function () {
function normalizeReturnBitrate(bitrate) {
// First try a small amount so that we don't hang up their mobile connection
return self.getDownloadSpeed(1000000).then(function (bitrate) {
if (!bitrate) {
if (bitrate < 1000000) {
return Math.round(bitrate * 0.8);
} else {
// If that produced a fairly high speed, try again with a larger size to get a more accurate result
return self.getDownloadSpeed(2400000).then(function (bitrate) {
return Math.round(bitrate * 0.8);
});
if (lastDetectedBitrate) {
return lastDetectedBitrate;
}
return Promise.reject();
}
var result = Math.round(bitrate * 0.8);
lastDetectedBitrate = result;
lastDetectedBitrateTime = new Date().getTime();
return result;
}
function detectBitrateInternal(tests, index, currentBitrate) {
if (index >= tests.length) {
return normalizeReturnBitrate(currentBitrate);
}
var test = tests[index];
return self.getDownloadSpeed(test.bytes).then(function (bitrate) {
if (bitrate < test.threshold) {
return normalizeReturnBitrate(bitrate);
} else {
return detectBitrateInternal(tests, index + 1, bitrate);
}
}, function () {
return normalizeReturnBitrate(currentBitrate);
});
}
self.detectBitrate = function () {
if (lastDetectedBitrate && (new Date().getTime() - (lastDetectedBitrateTime || 0)) <= 3600000) {
return Promise.resolve(lastDetectedBitrate);
}
return detectBitrateInternal([
{
bytes: 100000,
threshold: 5000000
},
{
bytes: 1000000,
threshold: 50000000
},
{
bytes: 3000000,
threshold: 50000000
}], 0);
};
/**
@ -768,6 +842,7 @@
self.logout = function () {
stopBitrateDetection();
self.closeWebSocket();
var done = function () {
@ -2561,6 +2636,8 @@
self.onAuthenticated(self, result);
}
redetectBitrate();
resolve(result);
}, reject);
@ -3311,6 +3388,8 @@
throw new Error("null options");
}
stopBitrateDetection();
var url = self.getUrl("Sessions/Playing");
return self.ajax({
@ -3439,6 +3518,8 @@
throw new Error("null options");
}
redetectBitrate();
var url = self.getUrl("Sessions/Playing/Stopped");
return self.ajax({

View File

@ -6,7 +6,10 @@
var localData;
function updateCache() {
cache.put('data', new Response(JSON.stringify(localData)));
if (cache) {
cache.put('data', new Response(JSON.stringify(localData)));
}
}
myStore.setItem = function (name, value) {
@ -38,10 +41,13 @@
try {
caches.open('embydata').then(function (result) {
cache = result;
localData = {};
});
if (self.caches) {
caches.open('embydata').then(function (result) {
cache = result;
localData = {};
});
}
} catch (err) {
console.log('Error opening cache: ' + err);

View File

@ -216,7 +216,7 @@
return connectUser;
};
var minServerVersion = '3.0.5994';
var minServerVersion = '3.0.7200';
self.minServerVersion = function (val) {
if (val) {
@ -447,6 +447,7 @@
if (options.reportCapabilities !== false) {
apiClient.reportCapabilities(capabilities);
}
apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection;
if (options.enableWebSocket !== false) {
console.log('calling apiClient.ensureWebSocket');
@ -1509,7 +1510,7 @@
var updateDevicePromise;
// Cache for 3 days
if (params.deviceId && (new Date().getTime() - (regInfo.lastValidDate || 0)) < 259200000) {
if (params.deviceId && (new Date().getTime() - (regInfo.lastValidDate || 0)) < 604800000) {
console.log('getRegistrationInfo has cached info');

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';
function processDownloadStatus(apiClient, serverInfo, options) {
console.log('[mediasync] Begin processDownloadStatus');
return localassetmanager.getServerItems(serverInfo.Id).then(function (items) {
console.log('[mediasync] Begin processDownloadStatus getServerItems completed');
var progressItems = items.filter(function (item) {
return item.SyncStatus === 'transferring' || item.SyncStatus === 'queued';
});
var p = Promise.resolve();
var cnt = 0;
progressItems.forEach(function (item) {
p = p.then(function () {
return reportTransfer(apiClient, item);
});
cnt++;
});
return p.then(function () {
console.log('[mediasync] Exit processDownloadStatus. Items reported: ' + cnt.toString());
return Promise.resolve();
});
});
}
function reportTransfer(apiClient, item) {
return localassetmanager.getItemFileSize(item.LocalPath).then(function (size) {
// The background transfer service on Windows leaves the file empty (size = 0) until it
// has been downloaded completely
if (size > 0) {
return apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function () {
item.SyncStatus = 'synced';
return localassetmanager.addOrUpdateLocalItem(item);
}, function (error) {
console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred", error);
item.SyncStatus = 'error';
return localassetmanager.addOrUpdateLocalItem(item);
});
} else {
return localassetmanager.isDownloadInQueue(item.SyncJobItemId).then(function (result) {
if (result) {
// just wait for completion
return Promise.resolve();
}
console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item.");
return localassetmanager.removeLocalItem(item).then(function () {
console.log('[mediasync] reportTransfer: Item deleted.');
return Promise.resolve();
}, function (err2) {
console.log('[mediasync] reportTransfer: Failed to delete item.', error);
return Promise.resolve();
});
});
}
}, function (error) {
console.error('[mediasync] reportTransfer: error on getItemFileSize. Deleting item.', error);
return localassetmanager.removeLocalItem(item).then(function () {
console.log('[mediasync] reportTransfer: Item deleted.');
return Promise.resolve();
}, function (err2) {
console.log('[mediasync] reportTransfer: Failed to delete item.', error);
return Promise.resolve();
});
});
}
function reportOfflineActions(apiClient, serverInfo) {
console.log('[mediasync] Begin reportOfflineActions');
return localassetmanager.getUserActions(serverInfo.Id).then(function (actions) {
if (!actions.length) {
console.log('[mediasync] Exit reportOfflineActions (no actions)');
return Promise.resolve();
}
return apiClient.reportOfflineActions(actions).then(function () {
return localassetmanager.deleteUserActions(actions).then(function () {
console.log('[mediasync] Exit reportOfflineActions (actions reported and deleted.)');
return Promise.resolve();
});
}, function (err) {
// delete those actions even on failure, because if the error is caused by
// the action data itself, this could otherwise lead to a situation that
// never gets resolved
console.error('[mediasync] error on apiClient.reportOfflineActions: ' + err.toString());
return localassetmanager.deleteUserActions(actions);
});
});
}
function syncData(apiClient, serverInfo, syncUserItemAccess) {
console.log('[mediasync] Begin syncData');
return localassetmanager.getServerItems(serverInfo.Id).then(function (items) {
var completedItems = items.filter(function (item) {
return (item) && ((item.SyncStatus === 'synced') || (item.SyncStatus === 'error'));
});
var request = {
TargetId: apiClient.deviceId(),
LocalItemIds: completedItems.map(function (xitem) { return xitem.ItemId; }),
OfflineUserIds: (serverInfo.Users || []).map(function (u) { return u.Id; })
};
return apiClient.syncData(request).then(function (result) {
return afterSyncData(apiClient, serverInfo, syncUserItemAccess, result).then(function () {
return Promise.resolve();
}, function () {
return Promise.resolve();
});
});
});
}
function afterSyncData(apiClient, serverInfo, enableSyncUserItemAccess, syncDataResult) {
console.log('[mediasync] Begin afterSyncData');
var p = Promise.resolve();
if (syncDataResult.ItemIdsToRemove) {
syncDataResult.ItemIdsToRemove.forEach(function (itemId) {
p = p.then(function () {
return removeLocalItem(itemId, serverInfo.Id);
});
});
}
if (enableSyncUserItemAccess) {
p = p.then(function () {
return syncUserItemAccess(syncDataResult, serverInfo.Id);
});
}
return p.then(function () {
console.log('[mediasync] Exit afterSyncData');
return Promise.resolve();
});
}
function removeLocalItem(itemId, serverId) {
console.log('[mediasync] Begin removeLocalItem');
return localassetmanager.getLocalItem(serverId, itemId).then(function (item) {
if (item) {
return localassetmanager.removeLocalItem(item);
}
return Promise.resolve();
});
}
function getNewMedia(apiClient, serverInfo, options) {
console.log('[mediasync] Begin getNewMedia');
return apiClient.getReadySyncItems(apiClient.deviceId()).then(function (jobItems) {
var p = Promise.resolve();
jobItems.forEach(function (jobItem) {
p = p.then(function () {
return getNewItem(jobItem, apiClient, serverInfo, options);
});
});
return p.then(function () {
console.log('[mediasync] Exit getNewMedia');
return Promise.resolve();
});
});
}
function getNewItem(jobItem, apiClient, serverInfo, options) {
console.log('[mediasync] Begin getNewItem');
var libraryItem = jobItem.Item;
return localassetmanager.getLocalItem(serverInfo.Id, libraryItem.Id).then(function (existingItem) {
console.log('[mediasync] getNewItem.getLocalItem completed');
if (existingItem) {
if (existingItem.SyncStatus === 'queued' || existingItem.SyncStatus === 'transferring' || existingItem.SyncStatus === 'synced') {
console.log('[mediasync] getNewItem.getLocalItem found existing item');
return Promise.resolve();
}
}
console.log('[mediasync] getNewItem.getLocalItem no existing item found');
return localassetmanager.createLocalItem(libraryItem, serverInfo, jobItem).then(function (localItem) {
console.log('[mediasync] getNewItem.createLocalItem completed');
localItem.SyncStatus = 'queued';
return downloadMedia(apiClient, jobItem, localItem, options).then(function () {
return getImages(apiClient, jobItem, localItem).then(function () {
return getSubtitles(apiClient, jobItem, localItem);
});
});
});
});
}
function downloadMedia(apiClient, jobItem, localItem, options) {
console.log('[mediasync] Begin downloadMedia');
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
api_key: apiClient.accessToken()
});
var localPath = localItem.LocalPath;
console.log('[mediasync] Downloading media. Url: ' + url + '. Local path: ' + localPath);
options = options || {};
return localassetmanager.downloadFile(url, localItem).then(function (filename) {
localItem.SyncStatus = 'transferring';
return localassetmanager.addOrUpdateLocalItem(localItem);
});
}
function getImages(apiClient, jobItem, localItem) {
console.log('[mediasync] Begin getImages');
return getNextImage(0, apiClient, localItem);
}
function getNextImage(index, apiClient, localItem) {
console.log('[mediasync] Begin getNextImage');
//if (index >= 4) {
// deferred.resolve();
// return;
//}
// Just for now while media syncing gets worked out
return Promise.resolve();
//var libraryItem = localItem.Item;
//var serverId = libraryItem.ServerId;
//var itemId = null;
//var imageTag = null;
//var imageType = "Primary";
//switch (index) {
// case 0:
// itemId = libraryItem.Id;
// imageType = "Primary";
// imageTag = (libraryItem.ImageTags || {})["Primary"];
// break;
// case 1:
// itemId = libraryItem.SeriesId;
// imageType = "Primary";
// imageTag = libraryItem.SeriesPrimaryImageTag;
// break;
// case 2:
// itemId = libraryItem.SeriesId;
// imageType = "Thumb";
// imageTag = libraryItem.SeriesPrimaryImageTag;
// break;
// case 3:
// itemId = libraryItem.AlbumId;
// imageType = "Primary";
// imageTag = libraryItem.AlbumPrimaryImageTag;
// break;
// default:
// break;
//}
//if (!itemId || !imageTag) {
// getNextImage(index + 1, apiClient, localItem, deferred);
// return;
//}
//downloadImage(apiClient, serverId, itemId, imageTag, imageType).then(function () {
// // For the sake of simplicity, limit to one image
// deferred.resolve();
// return;
// getNextImage(index + 1, apiClient, localItem, deferred);
//}, getOnFail(deferred));
}
function downloadImage(apiClient, serverId, itemId, imageTag, imageType) {
console.log('[mediasync] Begin downloadImage');
return localassetmanager.hasImage(serverId, itemId, imageTag).then(function (hasImage) {
if (hasImage) {
return Promise.resolve();
}
var imageUrl = apiClient.getImageUrl(itemId, {
tag: imageTag,
type: imageType,
api_key: apiClient.accessToken()
});
return localassetmanager.downloadImage(imageUrl, serverId, itemId, imageTag);
});
}
function getSubtitles(apiClient, jobItem, localItem) {
console.log('[mediasync] Begin getSubtitles');
if (!jobItem.Item.MediaSources.length) {
console.log("[mediasync] Cannot download subtitles because video has no media source info.");
return Promise.resolve();
}
var files = jobItem.AdditionalFiles.filter(function (f) {
return f.Type === 'Subtitles';
});
var mediaSource = jobItem.Item.MediaSources[0];
var p = Promise.resolve();
files.forEach(function (file) {
p = p.then(function () {
return getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource);
});
});
return p.then(function () {
console.log('[mediasync] Exit getSubtitles');
return Promise.resolve();
});
}
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
console.log('[mediasync] Begin getItemSubtitle');
var subtitleStream = mediaSource.MediaStreams.filter(function (m) {
return m.Type === 'Subtitle' && m.Index === file.Index;
})[0];
if (!subtitleStream) {
// We shouldn't get in here, but let's just be safe anyway
console.log("[mediasync] Cannot download subtitles because matching stream info wasn't found.");
return Promise.resolve();
}
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
Name: file.Name,
api_key: apiClient.accessToken()
});
var fileName = localassetmanager.getSubtitleSaveFileName(jobItem.OriginalFileName, subtitleStream.Language, subtitleStream.IsForced, subtitleStream.Codec);
var localFilePath = localassetmanager.getLocalFilePath(localItem, fileName);
return localassetmanager.downloadSubtitles(url, localFilePath).then(function (subtitlePath) {
subtitleStream.Path = subtitlePath;
return localassetmanager.addOrUpdateLocalItem(localItem);
});
}
return function () {
var self = this;
self.sync = function (apiClient, serverInfo, options) {
return reportOfflineActions(apiClient, serverInfo).then(function () {
console.log("[mediasync]************************************* Start sync");
// Do the first data sync
return syncData(apiClient, serverInfo, false).then(function () {
return processDownloadStatus(apiClient, serverInfo, options).then(function () {
return reportOfflineActions(apiClient, serverInfo).then(function () {
//// Do the first data sync
//return syncData(apiClient, serverInfo, false).then(function () {
// Download new content
return getNewMedia(apiClient, serverInfo, options).then(function () {
// Do the second data sync
return syncData(apiClient, serverInfo, false);
return syncData(apiClient, serverInfo, false).then(function () {
console.log("[mediasync]************************************* Exit sync");
});
});
//});
});
});
};
function reportOfflineActions(apiClient, serverInfo) {
console.log('Begin reportOfflineActions');
return LocalAssetManager.getOfflineActions(serverInfo.Id).then(function (actions) {
if (!actions.length) {
return Promise.resolve();
}
return apiClient.reportOfflineActions(actions).then(function () {
return LocalAssetManager.deleteOfflineActions(actions);
});
});
}
function syncData(apiClient, serverInfo, syncUserItemAccess) {
console.log('Begin syncData');
var deferred = DeferredBuilder.Deferred();
LocalAssetManager.getServerItemIds(serverInfo.Id).then(function (localIds) {
var request = {
TargetId: apiClient.deviceId(),
LocalItemIds: localIds,
OfflineUserIds: (serverInfo.Users || []).map(function (u) { return u.Id; })
};
apiClient.syncData(request).then(function (result) {
afterSyncData(apiClient, serverInfo, syncUserItemAccess, result, deferred);
}, getOnFail(deferred));
}, getOnFail(deferred));
return deferred.promise();
}
function afterSyncData(apiClient, serverInfo, enableSyncUserItemAccess, syncDataResult, deferred) {
console.log('Begin afterSyncData');
removeLocalItems(syncDataResult, serverInfo.Id).then(function (result) {
if (enableSyncUserItemAccess) {
syncUserItemAccess(syncDataResult, serverInfo.Id).then(function () {
deferred.resolve();
}, getOnFail(deferred));
}
else {
deferred.resolve();
}
}, getOnFail(deferred));
deferred.resolve();
}
function removeLocalItems(syncDataResult, serverId) {
console.log('Begin removeLocalItems');
var deferred = DeferredBuilder.Deferred();
removeNextLocalItem(syncDataResult.ItemIdsToRemove, 0, serverId, deferred);
return deferred.promise();
}
function removeNextLocalItem(itemIdsToRemove, index, serverId, deferred) {
var length = itemIdsToRemove.length;
if (index >= length) {
deferred.resolve();
return;
}
removeLocalItem(itemIdsToRemove[index], serverId).then(function () {
removeNextLocalItem(itemIdsToRemove, index + 1, serverId, deferred);
}, function () {
removeNextLocalItem(itemIdsToRemove, index + 1, serverId, deferred);
});
}
function removeLocalItem(itemId, serverId) {
console.log('Begin removeLocalItem');
return LocalAssetManager.removeLocalItem(itemId, serverId);
}
function getNewMedia(apiClient, serverInfo, options) {
console.log('Begin getNewMedia');
var deferred = DeferredBuilder.Deferred();
apiClient.getReadySyncItems(apiClient.deviceId()).then(function (jobItems) {
getNextNewItem(jobItems, 0, apiClient, serverInfo, options, deferred);
}, getOnFail(deferred));
return deferred.promise();
}
function getNextNewItem(jobItems, index, apiClient, serverInfo, options, deferred) {
var length = jobItems.length;
if (index >= length) {
deferred.resolve();
return;
}
var hasGoneNext = false;
var goNext = function () {
if (!hasGoneNext) {
hasGoneNext = true;
getNextNewItem(jobItems, index + 1, apiClient, serverInfo, options, deferred);
}
};
getNewItem(jobItems[index], apiClient, serverInfo, options).then(goNext, goNext);
}
function getNewItem(jobItem, apiClient, serverInfo, options) {
console.log('Begin getNewItem');
var deferred = DeferredBuilder.Deferred();
var libraryItem = jobItem.Item;
LocalAssetManager.createLocalItem(libraryItem, serverInfo, jobItem.OriginalFileName).then(function (localItem) {
downloadMedia(apiClient, jobItem, localItem, options).then(function (isQueued) {
if (isQueued) {
deferred.resolve();
return;
}
getImages(apiClient, jobItem, localItem).then(function () {
getSubtitles(apiClient, jobItem, localItem).then(function () {
apiClient.reportSyncJobItemTransferred(jobItem.SyncJobItemId).then(function () {
deferred.resolve();
}, getOnFail(deferred));
}, getOnFail(deferred));
}, getOnFail(deferred));
}, getOnFail(deferred));
}, getOnFail(deferred));
return deferred.promise();
}
function downloadMedia(apiClient, jobItem, localItem, options) {
console.log('Begin downloadMedia');
var deferred = DeferredBuilder.Deferred();
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
api_key: apiClient.accessToken()
});
var localPath = localItem.LocalPath;
console.log('Downloading media. Url: ' + url + '. Local path: ' + localPath);
options = options || {};
LocalAssetManager.downloadFile(url, localPath, options.enableBackgroundTransfer, options.enableNewDownloads).then(function (path, isQueued) {
if (isQueued) {
deferred.resolveWith(null, [true]);
return;
}
LocalAssetManager.addOrUpdateLocalItem(localItem).then(function () {
deferred.resolveWith(null, [false]);
}, getOnFail(deferred));
}, getOnFail(deferred));
return deferred.promise();
}
function getImages(apiClient, jobItem, localItem) {
console.log('Begin getImages');
var deferred = DeferredBuilder.Deferred();
getNextImage(0, apiClient, localItem, deferred);
return deferred.promise();
}
function getNextImage(index, apiClient, localItem, deferred) {
console.log('Begin getNextImage');
if (index >= 4) {
deferred.resolve();
return;
}
// Just for now while media syncing gets worked out
deferred.resolve();
//var libraryItem = localItem.Item;
//var serverId = libraryItem.ServerId;
//var itemId = null;
//var imageTag = null;
//var imageType = "Primary";
//switch (index) {
// case 0:
// itemId = libraryItem.Id;
// imageType = "Primary";
// imageTag = (libraryItem.ImageTags || {})["Primary"];
// break;
// case 1:
// itemId = libraryItem.SeriesId;
// imageType = "Primary";
// imageTag = libraryItem.SeriesPrimaryImageTag;
// break;
// case 2:
// itemId = libraryItem.SeriesId;
// imageType = "Thumb";
// imageTag = libraryItem.SeriesPrimaryImageTag;
// break;
// case 3:
// itemId = libraryItem.AlbumId;
// imageType = "Primary";
// imageTag = libraryItem.AlbumPrimaryImageTag;
// break;
// default:
// break;
//}
//if (!itemId || !imageTag) {
// getNextImage(index + 1, apiClient, localItem, deferred);
// return;
//}
//downloadImage(apiClient, serverId, itemId, imageTag, imageType).then(function () {
// // For the sake of simplicity, limit to one image
// deferred.resolve();
// return;
// getNextImage(index + 1, apiClient, localItem, deferred);
//}, getOnFail(deferred));
}
function downloadImage(apiClient, serverId, itemId, imageTag, imageType) {
console.log('Begin downloadImage');
var deferred = DeferredBuilder.Deferred();
LocalAssetManager.hasImage(serverId, itemId, imageTag).then(function (hasImage) {
if (hasImage) {
deferred.resolve();
return;
}
var imageUrl = apiClient.getImageUrl(itemId, {
tag: imageTag,
type: imageType,
api_key: apiClient.accessToken()
});
LocalAssetManager.downloadImage(imageUrl, serverId, itemId, imageTag).then(function () {
deferred.resolve();
}, getOnFail(deferred));
});
return deferred.promise();
}
function getSubtitles(apiClient, jobItem, localItem) {
console.log('Begin getSubtitles');
var deferred = DeferredBuilder.Deferred();
if (!jobItem.Item.MediaSources.length) {
console.log("Cannot download subtitles because video has no media source info.");
deferred.resolve();
return;
}
var files = jobItem.AdditionalFiles.filter(function (f) {
return f.Type === 'Subtitles';
});
var mediaSource = jobItem.Item.MediaSources[0];
getNextSubtitle(files, 0, apiClient, jobItem, localItem, mediaSource, deferred);
return deferred.promise();
}
function getNextSubtitle(files, index, apiClient, jobItem, localItem, mediaSource, deferred) {
var length = files.length;
if (index >= length) {
deferred.resolve();
return;
}
getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource).then(function () {
getNextSubtitle(files, index + 1, apiClient, jobItem, localItem, mediaSource, deferred);
}, function () {
getNextSubtitle(files, index + 1, apiClient, jobItem, localItem, mediaSource, deferred);
});
}
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
console.log('Begin getItemSubtitle');
var deferred = DeferredBuilder.Deferred();
var subtitleStream = mediaSource.MediaStreams.filter(function (m) {
return m.Type === 'Subtitle' && m.Index === file.Index;
})[0];
if (!subtitleStream) {
// We shouldn't get in here, but let's just be safe anyway
console.log("Cannot download subtitles because matching stream info wasn't found.");
deferred.reject();
return;
}
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
Name: file.Name,
api_key: apiClient.accessToken()
});
LocalAssetManager.downloadSubtitles(url, localItem, subtitleStream).then(function (subtitlePath) {
subtitleStream.Path = subtitlePath;
LocalAssetManager.addOrUpdateLocalItem(localItem).then(function () {
deferred.resolve();
}, getOnFail(deferred));
}, getOnFail(deferred));
return deferred.promise();
}
function syncUserItemAccess(syncDataResult, serverId) {
console.log('Begin syncUserItemAccess');
var deferred = DeferredBuilder.Deferred();
var itemIds = [];
for (var id in syncDataResult.ItemUserAccess) {
itemIds.push(id);
}
syncNextUserAccessForItem(itemIds, 0, syncDataResult, serverId, deferred);
return deferred.promise();
}
function syncNextUserAccessForItem(itemIds, index, syncDataResult, serverId, deferred) {
var length = itemIds.length;
if (index >= length) {
deferred.resolve();
return;
}
syncUserAccessForItem(itemIds[index], syncDataResult).then(function () {
syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
}, function () {
syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
});
}
function syncUserAccessForItem(itemId, syncDataResult) {
console.log('Begin syncUserAccessForItem');
var deferred = DeferredBuilder.Deferred();
LocalAssetManager.getUserIdsWithAccess(itemId, serverId).then(function (savedUserIdsWithAccess) {
var userIdsWithAccess = syncDataResult.ItemUserAccess[itemId];
if (userIdsWithAccess.join(',') === savedUserIdsWithAccess.join(',')) {
// Hasn't changed, nothing to do
deferred.resolve();
}
else {
LocalAssetManager.saveUserIdsWithAccess(itemId, serverId, userIdsWithAccess).then(function () {
deferred.resolve();
}, getOnFail(deferred));
}
}, getOnFail(deferred));
return deferred.promise();
}
function getOnFail(deferred) {
return function () {
deferred.reject();
};
}
};
//function syncUserItemAccess(syncDataResult, serverId) {
// console.log('[mediasync] Begin syncUserItemAccess');
// var itemIds = [];
// for (var id in syncDataResult.ItemUserAccess) {
// itemIds.push(id);
// }
// return syncNextUserAccessForItem(itemIds, 0, syncDataResult, serverId);
//}
//function syncNextUserAccessForItem(itemIds, index, syncDataResult, serverId) {
// var length = itemIds.length;
// if (index >= length) {
// return Promise.resolve
// return;
// }
// syncUserAccessForItem(itemIds[index], syncDataResult).then(function () {
// syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
// }, function () {
// syncNextUserAccessForItem(itemIds, index + 1, syncDataResult, serverId, deferred);
// });
//}
//function syncUserAccessForItem(itemId, syncDataResult) {
// console.log('[mediasync] Begin syncUserAccessForItem');
// var deferred = DeferredBuilder.Deferred();
// localassetmanager.getUserIdsWithAccess(itemId, serverId).then(function (savedUserIdsWithAccess) {
// var userIdsWithAccess = syncDataResult.ItemUserAccess[itemId];
// if (userIdsWithAccess.join(',') === savedUserIdsWithAccess.join(',')) {
// // Hasn't changed, nothing to do
// deferred.resolve();
// }
// else {
// localassetmanager.saveUserIdsWithAccess(itemId, serverId, userIdsWithAccess).then(function () {
// deferred.resolve();
// }, getOnFail(deferred));
// }
// }, getOnFail(deferred));
// return deferred.promise();
//}
//}
});

View File

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

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": {},
"ignore": [],
"version": "1.4.321",
"_release": "1.4.321",
"version": "1.4.390",
"_release": "1.4.390",
"_resolution": {
"type": "version",
"tag": "1.4.321",
"commit": "fb270e69c8391f62e762ee03d77a7b8a495c5a6f"
"tag": "1.4.390",
"commit": "075f424628a8208d15eca0ed024fe4d8f6bf43fa"
},
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.1",

View File

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

View File

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

View File

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

View File

@ -55,6 +55,11 @@
}
function isStyleSupported(prop, value) {
if (typeof window === 'undefined') {
return false;
}
// If no value is supplied, use "inherit"
value = arguments.length === 2 ? value : 'inherit';
// Try the native standard method first
@ -116,6 +121,50 @@
return false;
}
var _supportsCssAnimation;
var _supportsCssAnimationWithPrefix;
function supportsCssAnimation(allowPrefix) {
if (allowPrefix) {
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
return _supportsCssAnimationWithPrefix;
}
} else {
if (_supportsCssAnimation === true || _supportsCssAnimation === false) {
return _supportsCssAnimation;
}
}
var animation = false,
animationstring = 'animation',
keyframeprefix = '',
domPrefixes = ['Webkit', 'O', 'Moz'],
pfx = '',
elm = document.createElement('div');
if (elm.style.animationName !== undefined) { animation = true; }
if (animation === false && allowPrefix) {
for (var i = 0; i < domPrefixes.length; i++) {
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
animation = true;
break;
}
}
}
if (allowPrefix) {
_supportsCssAnimationWithPrefix = animation;
return _supportsCssAnimationWithPrefix;
} else {
_supportsCssAnimation = animation;
return _supportsCssAnimation;
}
}
var uaMatch = function (ua) {
ua = ua.toLowerCase();
@ -176,7 +225,7 @@
};
};
var userAgent = window.navigator.userAgent;
var userAgent = navigator.userAgent;
var matched = uaMatch(userAgent);
var browser = {};
@ -204,7 +253,7 @@
}
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
browser.animate = document.documentElement.animate != null;
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || userAgent.toLowerCase().indexOf('smarthub') !== -1;
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
browser.edgeUwp = browser.edge && userAgent.toLowerCase().indexOf('msapphost') !== -1;
@ -220,11 +269,17 @@
browser.slow = true;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
browser.touch = true;
if (typeof document !== 'undefined') {
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
browser.touch = true;
}
}
browser.keyboard = hasKeyboard(browser);
browser.supportsCssAnimation = supportsCssAnimation;
browser.osx = userAgent.toLowerCase().indexOf('os x') !== -1;
browser.iOS = browser.ipad || browser.iphone || browser.ipod;
return browser;
});

View File

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

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'],
function (datetime, imageLoader, connectionManager, itemHelper, mediaInfo, focusManager, indicators, globalize, layoutManager, appHost, dom) {
define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusManager', 'indicators', 'globalize', 'layoutManager', 'apphost', 'dom', 'browser', 'emby-button', 'css!./card', 'paper-icon-button-light', 'clearButtonStyle'],
function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser) {
'use strict';
var devicePixelRatio = window.devicePixelRatio || 1;
@ -144,6 +144,20 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
return 100 / 64;
}
return 100 / 72;
case 'overflowSmallBackdrop':
if (screenWidth >= 1200) {
return 100 / 18;
}
if (screenWidth >= 1000) {
return 100 / 24;
}
if (screenWidth >= 770) {
return 100 / 30;
}
if (screenWidth >= 540) {
return 100 / 40;
}
return 100 / 60;
default:
return 4;
}
@ -689,7 +703,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
return 'defaultCardColor' + getDefaultColorIndex(str);
}
function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin) {
function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) {
var html = '';
@ -714,10 +728,17 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
html += text;
html += "</div>";
valid++;
if (maxLines && valid >= maxLines) {
break;
}
}
}
if (forceLines) {
length = Math.min(lines.length, maxLines || lines.length);
while (valid < length) {
html += "<div class='" + cssClass + "'>&nbsp;</div>";
valid++;
@ -792,7 +813,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
if (showMediaTitle) {
var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item);
var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
includeParentInfo: options.includeParentInfoInTitle
});
lines.push(name);
}
@ -964,8 +987,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
if (item.RecordAnyChannel) {
lines.push(globalize.translate('sharedcomponents#AllChannels'));
}
else if (item.ChannelId) {
lines.push(item.ChannelName || '');
else {
lines.push(item.ChannelName || globalize.translate('sharedcomponents#OneChannel'));
}
}
@ -974,7 +997,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
lines.push('as ' + item.Role);
}
else if (item.Type) {
lines.push(globalize.translate('core#' + item.Type));
lines.push(globalize.translate('sharedcomponents#' + item.Type));
} else {
lines.push('');
}
@ -985,7 +1008,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
lines = [];
}
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, isOuterFooter && options.cardLayout && !options.centerText);
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, isOuterFooter && options.cardLayout && !options.centerText, options.lines);
if (progressHtml) {
html += progressHtml;
@ -1041,10 +1064,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
minutes = minutes || 1;
childText += globalize.translate('ValueMinutes', Math.round(minutes));
childText += globalize.translate('sharedcomponents#ValueMinutes', Math.round(minutes));
} else {
childText += globalize.translate('ValueMinutes', 0);
childText += globalize.translate('sharedcomponents#ValueMinutes', 0);
}
counts.push(childText);
@ -1236,7 +1259,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
}
if (overlayPlayButton && !item.IsPlaceHolder && (item.LocationType !== 'Virtual' || !item.MediaType || item.Type === 'Program') && item.Type !== 'Person' && item.PlayAccess === 'Full') {
overlayButtons += '<button is="paper-icon-button-light" class="cardOverlayButton itemAction autoSize" data-action="playmenu" onclick="return false;"><i class="md-icon">play_arrow</i></button>';
overlayButtons += '<button is="paper-icon-button-light" class="cardOverlayButton itemAction autoSize" data-action="play" onclick="return false;"><i class="md-icon">play_arrow</i></button>';
}
if (options.overlayMoreButton) {
@ -1268,7 +1291,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
cardContentClose = '</button>';
}
if (options.vibrant && imgUrl && !vibrantSwatch) {
var vibrantAttributes = options.vibrant && imgUrl && !vibrantSwatch ?
(' data-vibrant="' + cardFooterId + '" data-swatch="db"') :
'';
// Don't use the IMG tag with safari because it puts a white border around it
if (vibrantAttributes && !browser.safari) {
cardImageContainerOpen = '<div class="' + cardImageContainerClass + '">';
var imgClass = 'cardImage cardImage-img lazy';
@ -1279,10 +1307,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo
imgClass += ' coveredImage-img';
}
}
cardImageContainerOpen += '<img crossOrigin="Anonymous" class="' + imgClass + '" data-vibrant="' + cardFooterId + '" data-swatch="db" data-src="' + imgUrl + '" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />';
cardImageContainerOpen += '<img crossOrigin="Anonymous" class="' + imgClass + '"' + vibrantAttributes + ' data-src="' + imgUrl + '" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />';
} else {
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy"' + vibrantAttributes + ' data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
}
var cardScalableClass = options.cardLayout ? 'cardScalable visualCardBox-cardScalable' : 'cardScalable';

View File

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

View File

@ -110,30 +110,70 @@
return locale;
}
function getOptionList(options) {
var list = [];
for (var i in options) {
list.push({
name: i,
value: options[i]
});
}
return list;
}
function toLocaleString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ?
date.toLocaleString(currentLocale, options || {}) :
date.toLocaleString();
if (currentLocale && toLocaleTimeStringSupportsLocales) {
return date.toLocaleString(currentLocale, options);
}
return date.toLocaleString();
}
function toLocaleDateString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ?
date.toLocaleDateString(currentLocale, options || {}) :
date.toLocaleDateString();
if (currentLocale && toLocaleTimeStringSupportsLocales) {
return date.toLocaleDateString(currentLocale, options);
}
// This is essentially a hard-coded polyfill
var optionList = getOptionList(options);
if (optionList.length === 1 && optionList[0].name === 'weekday') {
var weekday = [];
weekday[0] = "Sun";
weekday[1] = "Mon";
weekday[2] = "Tue";
weekday[3] = "Wed";
weekday[4] = "Thu";
weekday[5] = "Fri";
weekday[6] = "Sat";
return weekday[date.getDay()];
}
return date.toLocaleDateString();
}
function toLocaleTimeString(date, options) {
options = options || {};
var currentLocale = getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ?
date.toLocaleTimeString(currentLocale, options || {}).toLowerCase() :
date.toLocaleTimeString().toLowerCase();
if (currentLocale && toLocaleTimeStringSupportsLocales) {
return date.toLocaleTimeString(currentLocale, options);
}
return date.toLocaleTimeString();
}
function getDisplayTime(date) {

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

View File

@ -94,12 +94,65 @@ define([], function () {
return windowSize;
}
var _animationEvent;
function whichAnimationEvent() {
if (_animationEvent) {
return _animationEvent;
}
var t,
el = document.createElement("div");
var animations = {
"animation": "animationend",
"OAnimation": "oAnimationEnd",
"MozAnimation": "animationend",
"WebkitAnimation": "webkitAnimationEnd"
};
for (t in animations) {
if (el.style[t] !== undefined) {
_animationEvent = animations[t];
return animations[t];
}
}
_animationEvent = 'animationend';
return _animationEvent;
}
var _transitionEvent;
function whichTransitionEvent() {
if (_transitionEvent) {
return _transitionEvent;
}
var t,
el = document.createElement("div");
var transitions = {
"transition": "transitionend",
"OTransition": "oTransitionEnd",
"MozTransition": "transitionend",
"WebkitTransition": "webkitTransitionEnd"
};
for (t in transitions) {
if (el.style[t] !== undefined) {
_transitionEvent = transitions[t];
return transitions[t];
}
}
_transitionEvent = 'transitionend';
return _transitionEvent;
}
return {
parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass,
parentWithTag: parentWithTag,
addEventListener: addEventListenerWithOptions,
removeEventListener: removeEventListenerWithOptions,
getWindowSize: getWindowSize
getWindowSize: getWindowSize,
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent
};
});

View File

@ -15,7 +15,7 @@
user-select: none;
cursor: pointer;
z-index: 0;
padding: 0.7em 0.57em;
padding: 1em .7em;
font-weight: normal;
vertical-align: middle;
border: 0;
@ -40,6 +40,18 @@
text-transform: uppercase;
}
.emby-button-focusscale {
transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center;
transform-origin: center center;
}
.emby-button-focusscale:focus {
transform: scale(1.16);
z-index: 1;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.emby-button > i {
/* For non-fab buttons that have icons */
font-size: 1.36em;
@ -50,7 +62,7 @@
.fab {
display: inline-flex;
border-radius: 50%;
background-color: #444;
background-color: rgba(170,170,190, .4);
padding: .6em;
box-sizing: border-box;
align-items: center;
@ -220,3 +232,14 @@
position: relative;
z-index: 1;
}
.icon-button-focusscale {
transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center;
transform-origin: center center;
}
.icon-button-focusscale:focus {
transform: scale(1.3);
z-index: 1;
}

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';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
@ -26,7 +26,7 @@
btn.appendChild(div);
}
div.addEventListener("animationend", function () {
div.addEventListener(dom.whichAnimationEvent(), function () {
div.parentNode.removeChild(div);
}, false);
}
@ -73,10 +73,15 @@
this.classList.add('emby-button');
if (browser.safari || browser.firefox || browser.noFlex) {
// Even though they support flex, it doesn't quite work with button elements
if (browser.firefox || browser.safari) {
this.classList.add('emby-button-noflex');
}
if (layoutManager.tv) {
this.classList.add('emby-button-focusscale');
}
if (enableAnimation()) {
dom.addEventListener(this, 'keydown', onKeyDown, {
passive: true

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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';
var EmbyTabs = Object.create(HTMLDivElement.prototype);
@ -97,6 +97,23 @@
}
}
function getFocusCallback(tabs, e) {
return function () {
onClick.call(tabs, e);
};
}
function onFocus(e) {
if (layoutManager.tv) {
if (this.focusTimeout) {
clearTimeout(this.focusTimeout);
}
this.focusTimeout = setTimeout(getFocusCallback(this, e), 700);
}
}
function onClick(e) {
var tabs = this;
@ -204,14 +221,37 @@
return;
}
this.classList.add('emby-tabs');
this.classList.add('focusable');
dom.addEventListener(this, 'click', onClick, {
passive: true
});
dom.addEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
initSelectionBar(this);
};
EmbyTabs.focus = function () {
var selected = this.querySelector('.' + activeButtonClass);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(this);
}
};
EmbyTabs.refresh = function () {
if (this.scroller) {
this.scroller.reload();
}
};
EmbyTabs.attachedCallback = function () {
initScroller(this);
@ -236,6 +276,10 @@
dom.removeEventListener(this, 'click', onClick, {
passive: true
});
dom.removeEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
this.selectionBar = null;
};

View File

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

View File

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

View File

@ -185,7 +185,13 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana
function translateKeyFromModule(key, module) {
return getDictionary(module)[key] || key;
var dictionary = getDictionary(module);
if (!dictionary) {
return key;
}
return dictionary[key] || key;
}
function replaceAll(str, find, replace) {

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) {
'use strict';
function saveCategories(context, options) {
var categories = [];
var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type');
if (chkCategorys[i].checked) {
categories.push(type);
}
}
if (categories.length >= 4) {
categories.push('series');
}
// differentiate between none and all
categories.push('all');
options.categories = categories;
}
function loadCategories(context, options) {
var selectedCategories = options.categories || [];
var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type');
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
}
}
function save(context) {
var i, length;
@ -65,7 +101,7 @@
}
}
function showEditor() {
function showEditor(options) {
return new Promise(function (resolve, reject) {
@ -106,6 +142,7 @@
}
save(dlg);
saveCategories(dlg, options);
if (settingsChanged) {
resolve();
@ -123,6 +160,7 @@
}
load(dlg);
loadCategories(dlg, options);
dialogHelper.open(dlg);
});
});

View File

@ -40,8 +40,29 @@
</div>
<br />
<label class="checkboxContainer">
<input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds" />
<input type="checkbox" is="emby-checkbox" class="chkColorCodedBackgrounds"/>
<span>${EnableColorCodedBackgrounds}</span>
</label>
<h3 class="checkboxListLabel">${Categories}</h3>
<div class="checkboxList">
<label>
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="movies" />
<span>${Movies}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="sports" />
<span>${Sports}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="kids" />
<span>${Kids}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" class="chkCategory" data-type="news" />
<span>${News}</span>
</label>
</div>
</form>
</div>

View File

@ -7,9 +7,18 @@
.tvGuideHeader {
white-space: nowrap;
width: 100%;
flex-direction: column;
flex-shrink: 0;
display: flex;
padding-left: 3.4em;
}
.guideHeaderDateSelection {
font-size: 86%;
padding: .4em 0;
}
.guideHeaderTimeslots {
display: flex;
}
.tvProgramSectionHeader {
@ -38,6 +47,7 @@
.channelTimeslotHeader {
flex-shrink: 0;
justify-content: center;
}
.timeslotHeaders {
@ -49,6 +59,7 @@
position: relative;
display: flex;
align-items: flex-start;
flex-grow: 1;
}
.channelPrograms {
@ -77,7 +88,7 @@
.currentTimeIndicatorArrowContainer {
position: absolute;
bottom: -1.3vh;
bottom: -1vh;
width: 100%;
color: #52B54B;
margin-left: .65vh;
@ -91,11 +102,11 @@
}
.currentTimeIndicatorArrow {
width: 4vh;
height: 4vh;
font-size: 4vh;
width: 3vh;
height: 3vh;
font-size: 3vh;
color: #52B54B;
margin-left: -2vh;
margin-left: -1.5vh;
}
.channelPrograms, .timeslotHeadersInner {
@ -171,29 +182,6 @@
}
}
.btnSelectDate {
padding-left: .5em;
text-transform: none;
font-weight: normal;
}
.btnSelectDateContent {
display: flex;
align-items: center;
justify-content: center;
}
.guideDateText {
font-size: 80%;
}
@media all and (min-width: 1600px) {
.guideDateText {
font-size: 92%;
}
}
.btnGuideViewSettings {
margin: 0;
flex-shrink: 0;
@ -203,13 +191,6 @@
font-size: 1.5em !important;
}
@media all and (max-width: 1280px) {
.btnGuideViewSettings {
display: none;
}
}
.selectDateIcon {
flex-shrink: 0;
}
@ -258,11 +239,12 @@
}
.timeslotHeader, .channelTimeslotHeader {
height: 3em;
height: 2.2em;
}
.programGrid {
padding-bottom: 4px;
flex-grow: 1;
}
.timeslotHeader {
@ -347,7 +329,7 @@
}
.programTextIcon-tv {
font-size: .7em;
font-size: .6em;
}
.guideChannelNumber {
@ -384,29 +366,6 @@
flex-shrink: 0;
}
.btnCategories {
margin: 0 .3em 0 .5em !important;
padding: 0 !important;
flex-shrink: 0;
background: rgba(40, 40, 40, .9);
border-radius: 0 !important;
width: 2.6em;
font-weight: normal !important;
position: relative;
}
.btnCategoriesText {
transform: rotate(90deg);
text-transform: uppercase;
transform-origin: left;
margin-left: 1.2em;
letter-spacing: .25em;
position: absolute;
top: 0;
margin-top: 1em;
white-space: nowrap;
}
.channelList {
display: flex;
flex-direction: column;
@ -416,11 +375,11 @@
contain: layout style;
}
.programCell, .channelHeaderCell, .btnSelectDate {
.programCell, .channelHeaderCell {
outline: none !important;
}
.programCell:focus, .channelHeaderCell:focus, .btnSelectDate:focus {
.programCell:focus, .channelHeaderCell:focus {
background-color: #555;
}
@ -433,25 +392,6 @@
opacity: .7;
}
.visibleGuideScroller::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.visibleGuideScroller::-webkit-scrollbar-button:start:decrement,
.visibleGuideScroller::-webkit-scrollbar-button:end:increment {
display: none;
}
.visibleGuideScroller::-webkit-scrollbar-track-piece {
background-color: #3b3b3b;
}
.visibleGuideScroller::-webkit-scrollbar-thumb:vertical, .visibleGuideScroller::-webkit-scrollbar-thumb:horizontal {
-webkit-border-radius: 2px;
background: #888 no-repeat center;
}
.guideOptions {
color: #eee;
flex-shrink: 0;
@ -464,8 +404,54 @@
.tvGuideHeader {
padding-left: 0;
}
}
.btnCategories {
display: none;
.guideRequiresUnlock {
margin: 1em auto;
text-align: center;
padding: 1em;
flex-shrink: 0;
}
.noRubberBanding {
/* This is needed to combat the rubber banding in iOS */
padding-bottom: 100px;
}
.guideDateTabsSlider {
text-align: center;
}
.guide-date-tab-button {
font-weight: 500 !important;
color: inherit !important;
padding-top: .3em !important;
padding-bottom: .3em !important;
opacity: .25;
}
.guide-date-tab-button.emby-tab-button-active {
color: #52B54B !important;
border-color: transparent !important;
opacity: 1;
font-weight: 500 !important;
}
.guide-date-tab-button:focus {
color: #52B54B !important;
opacity: 1;
}
.layout-tv .guide-date-tab-button:focus {
background-color: #52B54B !important;
border-radius: .25em !important;
color: #fff !important;
}
@media all and (min-width: 1200px) {
.guide-date-tab-button {
padding-left: 1em !important;
padding-right: 1em !important;
}
}

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';
function showViewSettings(instance) {
require(['guide-settings-dialog'], function (guideSettingsDialog) {
guideSettingsDialog.show().then(function () {
instance.refresh();
});
});
}
function showCategoryOptions(instance) {
require(['guide-categories-dialog'], function (guideCategoriesDialog) {
guideCategoriesDialog.show(instance.categoryOptions).then(function (categoryOptions) {
instance.categoryOptions = categoryOptions;
guideSettingsDialog.show(instance.categoryOptions).then(function () {
instance.refresh();
});
});
@ -38,15 +27,31 @@
var currentDate;
var currentStartIndex = 0;
var currentChannelLimit = 0;
var autoRefreshInterval;
self.refresh = function () {
currentDate = null;
reloadPage(options.element);
restartAutoRefresh();
};
self.pause = function () {
stopAutoRefresh();
};
self.resume = function (refreshData) {
if (refreshData) {
self.refresh();
} else {
restartAutoRefresh();
}
};
self.destroy = function () {
stopAutoRefresh();
events.off(serverNotifications, 'TimerCreated', onTimerCreated);
events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated);
events.off(serverNotifications, 'TimerCancelled', onTimerCancelled);
@ -58,6 +63,24 @@
items = {};
};
function restartAutoRefresh() {
stopAutoRefresh();
var intervalMs = 60000 * 15; // (minutes)
autoRefreshInterval = setInterval(function () {
self.refresh();
}, intervalMs);
}
function stopAutoRefresh() {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = null;
}
}
function normalizeDateToTimeslot(date) {
var minutesOffset = date.getMinutes() - cellCurationMinutes;
@ -152,7 +175,7 @@
});
}
function reloadGuide(context, newStartDate) {
function reloadGuide(context, newStartDate, focusProgramOnRender) {
var apiClient = connectionManager.currentApiClient();
@ -211,8 +234,8 @@
channelQuery.SortBy = "DatePlayed";
channelQuery.SortOrder = "Descending";
} else {
channelQuery.SortBy = "SortName";
channelQuery.SortOrder = "Ascending";
channelQuery.SortBy = null;
channelQuery.SortOrder = null;
}
var date = newStartDate;
@ -267,7 +290,7 @@
}).then(function (programsResult) {
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient);
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient, focusProgramOnRender);
hideLoading();
@ -482,7 +505,7 @@
timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"';
}
html += '<button data-action="' + clickAction + '"' + timerAttributes + ' data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
html += '<button data-action="' + clickAction + '"' + timerAttributes + ' data-channelid="' + program.ChannelId + '" data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
if (displayInnerContent) {
var guideProgramNameClass = "guideProgramName";
@ -605,7 +628,7 @@
imageLoader.lazyChildren(channelList);
}
function renderGuide(context, date, channels, programs, apiClient) {
function renderGuide(context, date, channels, programs, apiClient, focusProgramOnRender) {
//var list = [];
//channels.forEach(function(i) {
@ -663,7 +686,7 @@
items = {};
renderPrograms(context, date, channels, programs);
if (layoutManager.tv) {
if (focusProgramOnRender) {
var focusElem;
if (itemId) {
@ -723,21 +746,30 @@
}
}
function changeDate(page, date) {
function changeDate(page, date, focusProgramOnRender) {
clearCurrentTimeUpdateInterval();
var newStartDate = normalizeDateToTimeslot(date);
currentDate = newStartDate;
reloadGuide(page, newStartDate);
var dateText = datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' });
page.querySelector('.guideDateText').innerHTML = dateText;
reloadGuide(page, newStartDate, focusProgramOnRender);
}
var dateOptions = [];
function getDateTabText(date, isActive, tabIndex) {
var cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button';
var html = '<button is="emby-button" class="' + cssClass + '" data-index="' + tabIndex + '" data-date="' + date.getTime() + '">';
var tabText = datetime.toLocaleDateString(date, { weekday: 'short' });
tabText += '<br/>';
tabText += date.getDate();
html += '<div class="emby-button-foreground">' + tabText + '</div>';
html += '</button>';
return html;
}
function setDateRange(page, guideInfo) {
@ -756,18 +788,8 @@
start = new Date(Math.max(today, start));
dateOptions = [];
while (start <= end) {
dateOptions.push({
name: datetime.toLocaleDateString(start, { weekday: 'long', month: 'long', day: 'numeric' }),
id: start.getTime()
});
start.setDate(start.getDate() + 1);
start.setHours(0, 0, 0, 0);
}
var dateTabsHtml = '';
var tabIndex = 0;
var date = new Date();
@ -775,7 +797,21 @@
date.setTime(currentDate.getTime());
}
changeDate(page, date);
while (start <= end) {
var isActive = date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear();
dateTabsHtml += getDateTabText(start, isActive, tabIndex);
start.setDate(start.getDate() + 1);
start.setHours(0, 0, 0, 0);
tabIndex++;
}
page.querySelector('.emby-tabs-slider').innerHTML = dateTabsHtml;
page.querySelector('.guideDateTabs').refresh();
changeDate(page, date, layoutManager.tv);
}
function reloadPage(page) {
@ -790,36 +826,13 @@
});
}
function selectDate(page) {
var selectedDate = currentDate || new Date();
dateOptions.forEach(function (d) {
d.selected = new Date(d.id).getDate() === selectedDate.getDate();
});
require(['actionsheet'], function (actionsheet) {
actionsheet.show({
items: dateOptions,
title: globalize.translate('sharedcomponents#HeaderSelectDate'),
callback: function (id) {
var date = new Date();
date.setTime(parseInt(id));
changeDate(page, date);
}
});
});
}
function setScrollEvents(view, enabled) {
if (layoutManager.tv) {
require(['scrollHelper'], function (scrollHelper) {
var fn = enabled ? 'on' : 'off';
scrollHelper.centerFocus[fn](view.querySelector('.smoothScrollY'), false);
scrollHelper.centerFocus[fn](view.querySelector('.guideVerticalScroller'), false);
scrollHelper.centerFocus[fn](view.querySelector('.programGrid'), true);
});
}
@ -903,9 +916,9 @@
context.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
if (layoutManager.desktop) {
var visibleGuideScrollers = context.querySelectorAll('.guideScroller');
for (var i = 0, length = visibleGuideScrollers.length; i < length; i++) {
visibleGuideScrollers[i].classList.add('visibleGuideScroller');
var guideScrollers = context.querySelectorAll('.guideScroller');
for (var i = 0, length = guideScrollers.length; i < length; i++) {
guideScrollers[i].classList.add('darkScroller');
}
}
@ -914,6 +927,16 @@
programGrid.addEventListener('focus', onProgramGridFocus, true);
if (browser.iOS || browser.osx) {
context.querySelector('.channelsContainer').classList.add('noRubberBanding');
var programGridContainer = context.querySelector('.programGridContainer');
programGridContainer.classList.add('noRubberBanding');
programGridContainer.classList.remove('smoothScrollX');
programGridContainer.classList.add('hiddenScrollX');
}
dom.addEventListener(programGrid, 'scroll', function (e) {
onProgramGridScroll(context, this, timeslotHeaders);
}, {
@ -926,31 +949,37 @@
passive: true
});
context.querySelector('.btnSelectDate').addEventListener('click', function () {
selectDate(context);
});
context.querySelector('.btnUnlockGuide').addEventListener('click', function () {
currentStartIndex = 0;
reloadPage(context);
restartAutoRefresh();
});
context.querySelector('.btnNextPage').addEventListener('click', function () {
currentStartIndex += currentChannelLimit;
reloadPage(context);
restartAutoRefresh();
});
context.querySelector('.btnPreviousPage').addEventListener('click', function () {
currentStartIndex = Math.max(currentStartIndex - currentChannelLimit, 0);
reloadPage(context);
restartAutoRefresh();
});
context.querySelector('.btnGuideViewSettings').addEventListener('click', function () {
showViewSettings(self);
restartAutoRefresh();
});
context.querySelector('.btnCategories').addEventListener('click', function () {
showCategoryOptions(self);
context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
var tabButton = e.target.querySelectorAll('.guide-date-tab-button')[parseInt(e.detail.selectedTabIndex)];
if (tabButton) {
var date = new Date();
date.setTime(parseInt(tabButton.getAttribute('data-date')));
changeDate(context, date, false);
}
});
context.classList.add('tvguide');

View File

@ -1,36 +1,33 @@
<div class="tvGuideHeader">
<div class="channelTimeslotHeader">
<button is="emby-button" type="button" class="btnSelectDate block button-flat" style="color:inherit;">
<div class="btnSelectDateContent">
<div class="guideDateText">
</div>
<i class="md-icon selectDateIcon">&#xE5C5;</i>
<div class="guideHeaderDateSelection">
<div is="emby-tabs" class="guideDateTabs" data-selectionbar="false">
<div class="emby-tabs-slider guideDateTabsSlider">
</div>
</button>
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
<i class="md-icon btnGuideViewSettingsIcon">&#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;">
<button is="emby-button" type="button" class="btnCategories">
<div class="btnCategoriesText">${Categories}</div>
</button>
<div class="smoothScrollY guideVerticalScroller programContainer guideScroller" style="flex-grow: 1;">
<div class="channelsContainer">
<div class="channelList"></div>
</div>
<div class="programGridContainer programGrid smoothScrollX guideScroller" style="white-space: nowrap;">
<div class="guideHeaderTimeslots">
<div class="channelTimeslotHeader">
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings">
<i class="md-icon btnGuideViewSettingsIcon">&#xE5D3;</i>
</button>
</div>
<div class="timeslotHeaders smoothScrollX guideScroller" style="scroll-behavior: auto;"></div>
</div>
</div>
<div class="guideRequiresUnlock readOnlyContent hide" style="margin: 1em auto; text-align: center; padding: 1em; flex-shrink: 0;">
<div class="smoothScrollY guideVerticalScroller programContainer guideScroller">
<div class="channelsContainer">
<div class="channelList"></div>
</div>
<div class="programGridContainer programGrid smoothScrollX guideScroller" style="white-space: nowrap;">
</div>
</div>
<div class="guideRequiresUnlock hide">
<p class="unlockText"></p>
<button is="emby-button" type="button" class="raised button-submit block btnUnlockGuide">
<span>${UnlockGuide}</span>

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

View File

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

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';
var thresholdX;
var thresholdY;
var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn();
};
//var imagesWorker = new Worker(require.toUrl('.').split('?')[0] + '/imagesworker.js');
var supportsIntersectionObserver = function () {
if (window.IntersectionObserver) {
return true;
}
return false;
}();
function resetThresholds() {
var x = screen.availWidth;
var y = screen.availHeight;
if (browser.touch) {
x *= 1.5;
y *= 1.5;
}
thresholdX = x;
thresholdY = y;
}
if (!supportsIntersectionObserver) {
dom.addEventListener(window, "orientationchange", resetThresholds, { passive: true });
dom.addEventListener(window, 'resize', resetThresholds, { passive: true });
resetThresholds();
}
function isVisible(elem) {
return visibleinviewport(elem, true, thresholdX, thresholdY);
}
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
var self = {};
var enableFade = browser.animate && !browser.slow;
@ -65,7 +27,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
function fillImageElement(elem, source, enableEffects) {
imageFetcher.loadImage(elem, source).then(function () {
var fillingVibrant = elem.tagName !== 'IMG' ? false : fillVibrant(elem, source);
var fillingVibrant = fillVibrant(elem, source);
if (enableFade && !layoutManager.tv && enableEffects !== false && !fillingVibrant) {
fadeIn(elem);
@ -148,14 +110,17 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
requestIdleCallback(function () {
//var now = new Date().getTime();
var swatch = getVibrantInfo(img, url).split('|');
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
if (swatch.length) {
getVibrantInfoFromElement(img, url).then(function (vibrantInfo) {
var index = 0;
vibrantElement.style.backgroundColor = swatch[index];
vibrantElement.style.color = swatch[index + 1];
}
var swatch = vibrantInfo.split('|');
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
if (swatch.length) {
var index = 0;
vibrantElement.style.backgroundColor = swatch[index];
vibrantElement.style.color = swatch[index + 1];
}
});
});
/*
* Results into:
@ -167,6 +132,26 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
*/
}
function getVibrantInfoFromElement(elem, url) {
return new Promise(function (resolve, reject) {
require(['vibrant'], function () {
if (elem.tagName === 'IMG') {
resolve(getVibrantInfo(elem, url));
return;
}
var img = new Image();
img.onload = function () {
resolve(getVibrantInfo(img, url));
};
img.src = url;
});
});
}
function getSettingsKey(url) {
var parts = url.split('://');
@ -176,7 +161,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
url = url.split('?')[0];
var cacheKey = 'vibrant25';
var cacheKey = 'vibrant31';
//cacheKey = 'vibrant' + new Date().getTime();
return cacheKey + url;
}
@ -198,33 +183,21 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
value = '';
var swatch = swatches.DarkVibrant;
if (swatch) {
value += swatch.getHex() + '|' + swatch.getBodyTextColor();
}
//swatch = swatches.DarkMuted;
//if (swatch) {
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
//} else {
// value += '||';
//}
//swatch = swatches.Vibrant;
//if (swatch) {
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
//} else {
// value += '||';
//}
//swatch = swatches.Muted;
//if (swatch) {
// value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor();
//} else {
// value += '||';
//}
value += getSwatchString(swatch);
appSettings.set(getSettingsKey(url), value);
return value;
}
function getSwatchString(swatch) {
if (swatch) {
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
}
return '||';
}
function fadeIn(elem) {
var duration = layoutManager.tv ? 160 : 300;
@ -236,135 +209,9 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
elem.animate(keyframes, timing);
}
function cancelAll(tokens) {
for (var i = 0, length = tokens.length; i < length; i++) {
tokens[i] = true;
}
}
function unveilWithIntersection(images, root) {
var filledCount = 0;
var options = {};
//options.rootMargin = "300%";
var observer = new IntersectionObserver(function (entries) {
for (var j = 0, length2 = entries.length; j < length2; j++) {
var entry = entries[j];
var target = entry.target;
observer.unobserve(target);
fillImage(target);
filledCount++;
}
},
options
);
// Start observing an element
for (var i = 0, length = images.length; i < length; i++) {
observer.observe(images[i]);
}
}
function unveilElements(images, root) {
if (!images.length) {
return;
}
if (supportsIntersectionObserver) {
unveilWithIntersection(images, root);
return;
}
var filledImages = [];
var cancellationTokens = [];
function unveilInternal(tokenIndex) {
var anyFound = false;
var out = false;
// TODO: This out construct assumes left to right, top to bottom
for (var i = 0, length = images.length; i < length; i++) {
if (cancellationTokens[tokenIndex]) {
return;
}
if (filledImages[i]) {
continue;
}
var img = images[i];
if (!out && isVisible(img)) {
anyFound = true;
filledImages[i] = true;
fillImage(img);
} else {
if (anyFound) {
out = true;
}
}
}
if (!images.length) {
dom.removeEventListener(document, 'focus', unveil, {
capture: true,
passive: true
});
dom.removeEventListener(document, 'scroll', unveil, {
capture: true,
passive: true
});
dom.removeEventListener(document, wheelEvent, unveil, {
capture: true,
passive: true
});
dom.removeEventListener(window, 'resize', unveil, {
capture: true,
passive: true
});
}
}
function unveil() {
cancelAll(cancellationTokens);
var index = cancellationTokens.length;
cancellationTokens.length++;
setTimeout(function () {
unveilInternal(index);
}, 1);
}
dom.addEventListener(document, 'focus', unveil, {
capture: true,
passive: true
});
dom.addEventListener(document, 'scroll', unveil, {
capture: true,
passive: true
});
dom.addEventListener(document, wheelEvent, unveil, {
capture: true,
passive: true
});
dom.addEventListener(window, 'resize', unveil, {
capture: true,
passive: true
});
unveil();
}
function lazyChildren(elem) {
unveilElements(elem.getElementsByClassName('lazy'), elem);
lazyLoader.lazyChildren(elem, fillImage);
}
function getPrimaryImageAspectRatio(items) {
@ -439,6 +286,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser
self.lazyChildren = lazyChildren;
self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio;
self.getCachedVibrantInfo = getCachedVibrantInfo;
self.getVibrantInfoFromElement = getVibrantInfoFromElement;
return self;
});

View File

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

View File

@ -49,13 +49,30 @@ define(['css!./indicators.css', 'material-icons'], function () {
function enablePlayedIndicator(item) {
if (item.Type === "Series" || item.Type === "Season" || item.Type === "BoxSet" || item.MediaType === "Video" || item.MediaType === "Game" || item.MediaType === "Book") {
if (item.MediaType === 'Video') {
if (item.Type !== 'TvChannel') {
return true;
}
}
if (item.MediaType === 'Audio') {
if (item.Type === 'AudioPodcast') {
return true;
}
if (item.Type === 'AudioBook') {
return true;
}
}
if (item.Type === "Series" ||
item.Type === "Season" ||
item.Type === "BoxSet" ||
item.MediaType === "Game" ||
item.MediaType === "Book" ||
item.MediaType === "Recording") {
return true;
}
return false;
}

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') {
commands.push({
@ -174,7 +174,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
}
}
if (item.Type === 'Program') {
if (item.Type === 'Program' && options.record !== false) {
commands.push({
name: Globalize.translate('sharedcomponents#Record'),
@ -184,7 +184,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
if (user.Policy.IsAdministrator) {
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
commands.push({
name: globalize.translate('sharedcomponents#Refresh'),
id: 'refresh'
@ -233,7 +233,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
}
}
if (options.openAlbum !== false && item.AlbumId) {
if (options.openAlbum !== false && item.AlbumId && item.MediaType !== 'Photo') {
commands.push({
name: Globalize.translate('sharedcomponents#ViewAlbum'),
id: 'album'
@ -577,25 +577,16 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter',
return new Promise(function (resolve, reject) {
var itemId = item.Id;
require(['deleteHelper'], function (deleteHelper) {
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
require(['confirm'], function (confirm) {
confirm({
title: title,
text: msg,
confirmText: globalize.translate('sharedcomponents#Delete'),
primary: 'cancel'
deleteHelper.deleteItem({
item: item,
navigate: false
}).then(function () {
apiClient.deleteItem(itemId).then(function () {
resolve(true);
});
resolve(true);
}, reject);

View File

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

View File

@ -33,7 +33,6 @@
}
.cardOverlayFab {
background-color: #282828 !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 {
width: auto !important;
height: auto !important;
width: 1em !important;
height: 1em !important;
font-size: 143%;
border-radius: 500px;
background-color: #52B54B;
@ -166,12 +166,9 @@
align-items: center;
}
@supports (display: flex) {
.listItem, .listItemBody, .listItemMediaInfo {
display: flex;
contain: layout style;
}
.listItem, .listItemBody, .listItemMediaInfo {
display: flex;
contain: layout style;
}
@media all and (max-width: 800px) {

View File

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

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 {
date = datetime.parseISO8601Date(item.StartDate);
@ -453,6 +469,160 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
return '';
}
function getResolutionText(item) {
if (!item.MediaSources || !item.MediaSources.length) {
return null;
}
return item.MediaSources[0].MediaStreams.filter(function (i) {
return i.Type === 'Video';
}).map(function (i) {
if (i.Height) {
if (i.Width >= 3800) {
return '4K';
}
if (i.Width >= 2500) {
return '1440P';
}
if (i.Width >= 1900) {
return '1080P';
}
if (i.Width >= 1260) {
return '720P';
}
if (i.Width >= 700) {
return '480P';
}
}
return null;
})[0];
}
function getAudioStreamForDisplay(item) {
if (!item.MediaSources) {
return null;
}
var mediaSource = item.MediaSources[0];
if (!mediaSource) {
return null;
}
return (mediaSource.MediaStreams || []).filter(function (i) {
return i.Type === 'Audio' && (i.Index === mediaSource.DefaultAudioStreamIndex || mediaSource.DefaultAudioStreamIndex == null);
})[0];
}
function getMediaInfoStats(item, options) {
options = options || {};
var list = [];
if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) {
list.push({
type: 'added',
text: globalize.translate('sharedcomponents#AddedOnValue', datetime.toLocaleDateString(datetime.parseISO8601Date(item.DateCreated)))
});
}
if (!item.MediaSources) {
return list;
}
var mediaSource = item.MediaSources[0];
if (!mediaSource) {
return list;
}
var videoStream = (mediaSource.MediaStreams || []).filter(function (i) {
return i.Type === 'Video';
})[0] || {};
var audioStream = getAudioStreamForDisplay(item) || {};
if (item.VideoType === 'Dvd') {
list.push({
type: 'mediainfo',
text: 'Dvd'
});
}
if (item.VideoType === 'BluRay') {
list.push({
type: 'mediainfo',
text: 'BluRay'
});
}
//if (mediaSource.Container) {
// html += '<div class="mediaInfoIcon mediaInfoText">' + mediaSource.Container + '</div>';
//}
var resolutionText = getResolutionText(item);
if (resolutionText) {
list.push({
type: 'mediainfo',
text: resolutionText
});
}
if (videoStream.Codec) {
list.push({
type: 'mediainfo',
text: videoStream.Codec
});
}
var channels = audioStream.Channels;
var channelText;
if (channels === 8) {
channelText = '7.1';
} else if (channels === 7) {
channelText = '6.1';
} else if (channels === 6) {
channelText = '5.1';
} else if (channels === 2) {
channelText = '2.0';
}
if (channelText) {
list.push({
type: 'mediainfo',
text: channelText
});
}
if (audioStream.Codec === 'dca' && audioStream.Profile) {
list.push({
type: 'mediainfo',
text: audioStream.Profile
});
} else if (audioStream.Codec) {
list.push({
type: 'mediainfo',
text: audioStream.Codec
});
}
return list;
}
return {
getMediaInfoHtml: getPrimaryMediaInfoHtml,
fill: fillPrimaryMediaInfo,
@ -461,6 +631,7 @@ define(['datetime', 'globalize', 'embyRouter', 'itemHelper', 'material-icons', '
getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml,
getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml,
fillPrimaryMediaInfo: fillPrimaryMediaInfo,
fillSecondaryMediaInfo: fillSecondaryMediaInfo
fillSecondaryMediaInfo: fillSecondaryMediaInfo,
getMediaInfoStats: getMediaInfoStats
};
});

View File

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

View File

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

View File

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

View File

@ -127,6 +127,12 @@
select.innerHTML = html;
select.value = userSettings.get('playlisteditor-lastplaylistid') || '';
// If the value is empty set it again, in case we tried to set a lastplaylistid that is no longer valid
if (!select.value) {
select.value = '';
}
triggerChange(select);
loading.hide();

View File

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

View File

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

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

View File

@ -1,47 +1,4 @@
<style>
.visibilityHide {
visibility: hidden;
}
.recordingButton {
margin-left: 0;
min-width: 10em;
font-size: 92%;
}
.recordingIcon {
font-size: 1.3em !important;
}
.recordingIcon-active {
color: #cc3333;
}
.manageButtonText {
text-transform: none;
}
@media all and (max-width: 440px) {
.manageButtonText {
display: none !important;
}
.recordingButton {
width: auto;
margin-right: 1.5em !important;
}
}
@media all and (min-width: 440px) {
.manageButtonIcon {
font-size: 90% !important;
}
}
</style>
<div class="convertRecordingsContainer hide" style="padding: 1.25em 1.5em; background: #242424; border-radius: 3px; margin: 1em 0 2em;">
<div class="convertRecordingsContainer hide" style="padding: 1.25em 1.5em; background: #242424; border-radius: 3px; margin: 1em 0 2em;">
<h1 style="margin: .25em 0 .5em;">${HeaderConvertYourRecordings}</h1>
<div class="fieldDescription">${PromoConvertRecordingsToStreamingFormat}</div>
<br />
@ -58,27 +15,27 @@
</div>
<div class="recordingFields hide">
<div class="recordSeriesContainer hide" style="display: flex; align-items: center;margin-bottom:.8em;">
<div class="recordSeriesContainer recordingFields-buttons hide">
<div>
<button is="emby-button" type="button" class="raised button-cancel recordingButton seriesRecordingButton">
<i class="md-icon recordingIcon">&#xE062;</i>
<span class="buttonText">${RecordSeries}</span>
</button>
</div>
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageSeriesRecording visibilityHide">
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageSeriesRecording hide">
<i class="md-icon manageButtonIcon">settings</i>
<span class="manageButtonText">${SeriesSettings}</span>
</button>
</div>
<div style="display: flex; align-items: center;">
<div class="recordingFields-buttons">
<div>
<button is="emby-button" type="button" class="raised button-cancel recordingButton singleRecordingButton">
<i class="md-icon recordingIcon">&#xE061;</i>
<span class="buttonText">${Record}</span>
</button>
</div>
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageRecording visibilityHide">
<button is="emby-button" type="button" class="button-flat secondaryText manageRecordingButton btnManageRecording hide">
<i class="md-icon manageButtonIcon">settings</i>
<span class="manageButtonText">${Settings}</span>
</button>

View File

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

View File

@ -98,15 +98,24 @@
function reload(context, id) {
loading.show();
currentItemId = id;
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
renderTimer(context, result, apiClient);
loading.show();
if (typeof id === 'string') {
currentItemId = id;
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
renderTimer(context, result, apiClient);
loading.hide();
});
} else if (id) {
currentItemId = id.Id;
renderTimer(context, id, apiClient);
loading.hide();
});
}
}
function fillKeepUpTo(context) {
@ -130,6 +139,10 @@
context.querySelector('.selectKeepUpTo').innerHTML = html;
}
function onFieldChange(e) {
this.querySelector('.btnSubmit').click();
}
function embed(itemId, serverId, options) {
@ -163,9 +176,8 @@
dlg.querySelector('.dialogContentInner').className = '';
dlg.classList.remove('hide');
dlg.addEventListener('change', function () {
dlg.querySelector('.btnSubmit').click();
});
dlg.removeEventListener('change', onFieldChange);
dlg.addEventListener('change', onFieldChange);
currentDialog = dlg;

View File

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

View File

@ -42,7 +42,7 @@
html += '<br />';
html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#ButtonOk') + '</button>';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#Refresh') + '</button>';
html += '</div>';
html += '</form>';

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

View File

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

View File

@ -33,3 +33,22 @@
width: 0 !important;
display: none;
}
.darkScroller::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.darkScroller::-webkit-scrollbar-button:start:decrement,
.darkScroller::-webkit-scrollbar-button:end:increment {
display: none;
}
.darkScroller::-webkit-scrollbar-track-piece {
background-color: #3b3b3b;
}
.darkScroller::-webkit-scrollbar-thumb:vertical, .darkScroller::-webkit-scrollbar-thumb:horizontal {
-webkit-border-radius: 2px;
background: #888 no-repeat center;
}

View File

@ -225,6 +225,8 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
var serverId = item.ServerId;
var type = item.Type;
var playableItemId = type === 'Program' ? item.ChannelId : item.Id;
if (action === 'link') {
showItem(item, {
@ -238,7 +240,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
}
else if (action === 'instantmix') {
playbackManager.instantMix(id, serverId);
playbackManager.instantMix(playableItemId, serverId);
}
else if (action === 'play') {
@ -246,7 +248,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
playbackManager.play({
ids: [id],
ids: [playableItemId],
startPositionTicks: startPositionTicks,
serverId: serverId
});
@ -410,11 +412,17 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter', 'g
}
}
function getShortcutAttributesHtml(item) {
return 'data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"';
}
return {
on: on,
off: off,
onClick: onClick,
showContextMenu: showContextMenu
showContextMenu: showContextMenu,
getShortcutAttributesHtml: getShortcutAttributesHtml
};
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,46 +1,46 @@
{
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock this feature with a small one-time purchase, or with an active Emby Premiere subscription.",
"MessageUnlockAppWithSupporter": "Unlock this feature with an active Emby Premiere subscription.",
"MessageUnlockAppWithPurchaseOrSupporter": "\u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03ba\u03b1\u03c4\u03b1\u03b2\u03ac\u03bb\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ad\u03bd\u03b1 \u03c0\u03bf\u03bb\u03cd \u03bc\u03b9\u03ba\u03c1\u03cc \u03ba\u03cc\u03c3\u03c4\u03bf\u03c2 \u03ae \u03bc\u03b5 \u03bc\u03af\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c4\u03bf Emby Premiere.",
"MessageUnlockAppWithSupporter": "\u039e\u03b5\u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03c3\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03bc\u03b5 \u03bc\u03af\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae \u03c3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c4\u03bf Emby Premiere.",
"MessageToValidateSupporter": "If you have an active Emby Premiere subscription, ensure you've setup Emby Premiere in your Emby Server Dashboard, which you can access by clicking Emby Premiere within the main menu.",
"ValueSpecialEpisodeName": "Special - {0}",
"Share": "Share",
"Add": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5",
"ServerUpdateNeeded": "This Emby Server needs to be updated. To download the latest version, please visit {0}",
"LiveTvGuideRequiresUnlock": "The Live TV Guide is currently limited to {0} channels. Click the unlock button to learn how to enjoy the full experience.",
"AttributeNew": "New",
"AttributeNew": "\u039d\u03ad\u03bf",
"Premiere": "Premiere",
"Live": "Live",
"Repeat": "Repeat",
"Live": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ac",
"Repeat": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7",
"TrackCount": "{0} tracks",
"ItemCount": "{0} items",
"ReleaseYearValue": "Release year: {0}",
"ReleaseYearValue": "\u0388\u03c4\u03bf\u03c2 \u03ba\u03c5\u03ba\u03bb\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2: {0} \n",
"OriginalAirDateValue": "Original air date: {0}",
"EndsAtValue": "Ends at {0}",
"OptionSundayShort": "Sun",
"OptionMondayShort": "Mon",
"OptionTuesdayShort": "Tue",
"OptionWednesdayShort": "Wed",
"OptionThursdayShort": "Thu",
"OptionFridayShort": "Fri",
"OptionSaturdayShort": "Sat",
"HeaderSelectDate": "Select Date",
"OptionSundayShort": "\u039a\u03c5\u03c1",
"OptionMondayShort": "\u0394\u03b5\u03c5",
"OptionTuesdayShort": "\u03a4\u03c1\u03b9",
"OptionWednesdayShort": "\u03a4\u03b5\u03c4",
"OptionThursdayShort": "\u03a0\u03b5\u03bc",
"OptionFridayShort": "\u03a0\u03b1\u03c1",
"OptionSaturdayShort": "\u03a3\u03b1\u03b2",
"HeaderSelectDate": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1\u03c2",
"ButtonOk": "Ok",
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
"ButtonGotIt": "Got It",
"ButtonRestart": "Restart",
"ButtonRestart": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
"RecordingCancelled": "Recording cancelled.",
"SeriesCancelled": "Series cancelled.",
"RecordingScheduled": "Recording scheduled.",
"SeriesRecordingScheduled": "Series recording scheduled.",
"HeaderNewRecording": "New Recording",
"Sunday": "Sunday",
"Monday": "Monday",
"Tuesday": "Tuesday",
"Wednesday": "Wednesday",
"Thursday": "Thursday",
"Friday": "Friday",
"Saturday": "Saturday",
"Days": "Days",
"HeaderNewRecording": "\u039d\u03ad\u03b1 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae",
"Sunday": "\u039a\u03c5\u03c1\u03b9\u03b1\u03ba\u03ae",
"Monday": "\u0394\u03b5\u03c5\u03c4\u03ad\u03c1\u03b1",
"Tuesday": "\u03a4\u03c1\u03af\u03c4\u03b7",
"Wednesday": "\u03a4\u03b5\u03c4\u03ac\u03c1\u03c4\u03b7",
"Thursday": "\u03a0\u03ad\u03bc\u03c0\u03c4\u03b7",
"Friday": "\u03a0\u03b1\u03c1\u03b1\u03c3\u03ba\u03b5\u03c5\u03ae",
"Saturday": "\u03a3\u03ac\u03b2\u03b2\u03b1\u03c4\u03bf",
"Days": "\u0397\u03bc\u03ad\u03c1\u03b5\u03c2",
"RecordSeries": "Record series",
"HeaderCinemaMode": "Cinema Mode",
"HeaderCloudSync": "Cloud Sync",
@ -50,52 +50,52 @@
"CoverArtFeatureDescription": "Cover Art creates fun covers and other treatments to help you personalize your media images.",
"CoverArt": "Cover Art",
"CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.",
"HeaderFreeApps": "Free Emby Apps",
"HeaderFreeApps": "\u0394\u03c9\u03c1\u03b5\u03ac\u03bd \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 Emby",
"FreeAppsFeatureDescription": "Enjoy free access to Emby apps for your devices.",
"HeaderBecomeProjectSupporter": "Get Emby Premiere",
"HeaderBecomeProjectSupporter": "\u0391\u03c0\u03cc\u03ba\u03c4\u03b7\u03c3\u03b5 \u03a3\u03c5\u03bd\u03b4\u03c1\u03bf\u03bc\u03ae Emby Premiere",
"MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.",
"LabelEmailAddress": "E-mail address:",
"LabelEmailAddress": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 E-mail",
"PromoConvertRecordingsToStreamingFormat": "Automatically convert recordings to a streaming friendly format with Emby Premiere. Recordings will be converted on the fly to MP4 or MKV, based on Emby server settings.",
"FeatureRequiresEmbyPremiere": "This feature requires an active Emby Premiere subscription.",
"HeaderConvertYourRecordings": "Convert Your Recordings",
"Record": "Record",
"Record": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae",
"Save": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7",
"Edit": "Edit",
"Edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1",
"Download": "Download",
"Advanced": "Advanced",
"Delete": "Delete",
"HeaderDeleteItem": "Delete Item",
"Delete": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae",
"HeaderDeleteItem": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u0391\u03bd\u03c4\u03b9\u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5",
"ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"Refresh": "Refresh",
"Refresh": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7",
"RefreshQueued": "Refresh queued.",
"AddToCollection": "Add to collection",
"AddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"HeaderAddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"NewCollection": "New Collection",
"LabelCollection": "Collection:",
"NewCollection": "\u039d\u03ad\u03b1 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"LabelCollection": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae:",
"Help": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1",
"NewCollectionHelp": "Collections allow you to create personalized groupings of movies and other library content.",
"SearchForCollectionInternetMetadata": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03b3\u03b9\u03b1 \u03b5\u03be\u03ce\u03c6\u03c5\u03bb\u03bb\u03bf \u03ba\u03b1\u03b9 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2",
"LabelName": "\u038c\u03bd\u03bf\u03bc\u03b1:",
"NewCollectionNameExample": "\u03a0\u03b1\u03c1\u03ac\u03b4\u03b5\u03b9\u03b3\u03bc\u03b1: \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae \"\u03a0\u03cc\u03bb\u03b5\u03bc\u03bf\u03c2 \u03c4\u03c9\u03bd \u0386\u03c3\u03c4\u03c1\u03c9\u03bd\"",
"MessageItemsAdded": "Items added.",
"OptionNew": "New...",
"LabelPlaylist": "Playlist:",
"AddToPlaylist": "Add to playlist",
"HeaderAddToPlaylist": "Add to Playlist",
"Subtitles": "Subtitles",
"SearchForSubtitles": "Search for Subtitles",
"OptionNew": "\u039d\u03ad\u03bf...",
"LabelPlaylist": "\u039b\u03af\u03c3\u03c4\u03b1:",
"AddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u03bb\u03af\u03c3\u03c4\u03b1",
"HeaderAddToPlaylist": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03b5 \u039b\u03af\u03c3\u03c4\u03b1",
"Subtitles": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9",
"SearchForSubtitles": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03a5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd",
"LabelLanguage": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1",
"Search": "Search",
"Search": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7",
"NoSubtitleSearchResultsFound": "No results found.",
"File": "File",
"MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
"ConfirmDeletion": "Confirm Deletion",
"MySubtitles": "My Subtitles",
"ConfirmDeletion": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03af\u03c9\u03c3\u03b7 \u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2",
"MySubtitles": "\u039f\u03b9 \u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03bc\u03bf\u03c5",
"MessageDownloadQueued": "Download queued.",
"EditSubtitles": "Edit subtitles",
"EditSubtitles": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd",
"UnlockGuide": "Unlock Guide",
"RefreshMetadata": "Refresh Metadata",
"ReplaceExistingImages": "Replace existing images",
"RefreshMetadata": "\u0391\u03bd\u03b1\u03bd\u03ad\u03c9\u03c3\u03b7 \u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd",
"ReplaceExistingImages": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03c3\u03c9\u03bd \u03b5\u03b9\u03ba\u03cc\u03bd\u03c9\u03bd",
"ReplaceAllMetadata": "Replace all metadata",
"SearchForMissingMetadata": "Search for missing metadata",
"LabelRefreshMode": "Refresh mode:",
@ -139,7 +139,7 @@
"MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?",
"Error": "Error",
"VoiceInput": "Voice Input",
"LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd:",
"LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5:",
"LabelPath": "Path:",
"LabelTitle": "Title:",
"LabelOriginalTitle": "Original title:",
@ -147,7 +147,7 @@
"LabelDateAdded": "Date added:",
"ConfigureDateAdded": "Configure how date added is determined in the Emby Server dashboard under Library settings",
"LabelStatus": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7:",
"LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
"LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2:",
"LabelArtistsHelp": "Separate multiple using ;",
"LabelAlbumArtists": "Album artists:",
"LabelAlbum": "Album:",
@ -162,7 +162,7 @@
"LabelOverview": "Overview:",
"LabelShortOverview": "Short overview:",
"LabelReleaseDate": "Release date:",
"LabelYear": "Year:",
"LabelYear": "\u0388\u03c4\u03bf\u03c2:",
"LabelPlaceOfBirth": "Place of birth:",
"LabelAirDays": "Air days:",
"LabelAirTime": "Air time:",
@ -182,7 +182,7 @@
"LabelAirsBeforeSeason": "Airs before season:",
"LabelAirsAfterSeason": "Airs after season:",
"LabelAirsBeforeEpisode": "Airs before episode:",
"HeaderExternalIds": "External Id's:",
"HeaderExternalIds": "External Ids:",
"HeaderDisplaySettings": "Display Settings",
"LabelTreatImageAs": "Treat image as:",
"LabelDisplayOrder": "Display order:",
@ -196,7 +196,7 @@
"LabelMetadataDownloadLanguage": "Preferred download language:",
"LabelLockItemToPreventChanges": "Lock this item to prevent future changes",
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.",
"LabelCountry": "\u03a7\u03ce\u03c1\u03b1",
"LabelCountry": "\u03a7\u03ce\u03c1\u03b1:",
"LabelDynamicExternalId": "{0} Id:",
"LabelBirthYear": "Birth year:",
"LabelBirthDate": "Birth date:",
@ -220,7 +220,7 @@
"Runtime": "Runtime",
"ProductionLocations": "Production locations",
"BirthLocation": "Birth location",
"ParentalRating": "Parental Rating",
"ParentalRating": "\u039a\u03b1\u03c4\u03b1\u03bb\u03bb\u03b7\u03bb\u03cc\u03c4\u03b7\u03c4\u03b1",
"Name": "Name",
"Overview": "Overview",
"LabelType": "Type:",
@ -343,12 +343,16 @@
"ButtonRestorePreviousPurchase": "Restore Purchase",
"ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}",
"ButtonAlreadyPaid": "Already Paid?",
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderAlreadyPaid": "Already Paid?",
"ButtonPlayOneMinute": "Play One Minute",
"PlaceFavoriteChannelsAtBeginning": "Place favorite channels at the beginning",
"HeaderUnlockFeature": "Unlock Feature",
"MessageDidYouKnowCinemaMode": "Did you know that with Emby Premiere, you can enhance your experience with features like Cinema Mode?",
"MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature.",
"HeaderPlayMyMedia": "Play my Media",
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere"
"HeaderDiscoverEmbyPremiere": "Discover Emby Premiere",
"OneChannel": "One channel",
"ConfirmRemoveDownload": "Remove download?",
"AddedOnValue": "Added {0}"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More