mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into config
This commit is contained in:
commit
20391c52e3
13 changed files with 473 additions and 217 deletions
|
@ -78,12 +78,15 @@
|
|||
"overrides": [
|
||||
{
|
||||
"test": [
|
||||
"src/components/autoFocuser.js",
|
||||
"src/components/cardbuilder/cardBuilder.js",
|
||||
"src/components/dom.js",
|
||||
"src/components/filedownloader.js",
|
||||
"src/components/filesystem.js",
|
||||
"src/components/input/keyboardnavigation.js",
|
||||
"src/components/sanatizefilename.js",
|
||||
"src/scripts/settings/webSettings.js"
|
||||
"src/scripts/settings/webSettings.js",
|
||||
"src/components/scrollManager.js"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-modules-amd"
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
define(["focusManager", "layoutManager"], function (focusManager, layoutManager) {
|
||||
"use strict";
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for performing auto-focus.
|
||||
* @module components/autoFocuser
|
||||
*/
|
||||
|
||||
import focusManager from "focusManager";
|
||||
import layoutManager from "layoutManager";
|
||||
|
||||
/**
|
||||
* Previously selected element.
|
||||
*/
|
||||
var activeElement;
|
||||
let activeElement;
|
||||
|
||||
/**
|
||||
* Returns true if AutoFocuser is enabled.
|
||||
* Returns _true_ if AutoFocuser is enabled.
|
||||
*/
|
||||
function isEnabled() {
|
||||
export function isEnabled() {
|
||||
return layoutManager.tv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start AutoFocuser
|
||||
* Start AutoFocuser.
|
||||
*/
|
||||
function enable() {
|
||||
export function enable() {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
@ -28,24 +35,19 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager)
|
|||
console.debug("AutoFocuser enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array from some source.
|
||||
*/
|
||||
var arrayFrom = Array.prototype.from || function (src) {
|
||||
return Array.prototype.slice.call(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus on a suitable element, taking into account the previously selected.
|
||||
* @param {HTMLElement} [container] - Element to limit scope.
|
||||
* @returns {HTMLElement} Focused element.
|
||||
*/
|
||||
function autoFocus(container) {
|
||||
export function autoFocus(container) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
container = container || document.body;
|
||||
|
||||
var candidates = [];
|
||||
let candidates = [];
|
||||
|
||||
if (activeElement) {
|
||||
// These elements are recreated
|
||||
|
@ -62,10 +64,10 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager)
|
|||
candidates.push(activeElement);
|
||||
}
|
||||
|
||||
candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnResume")));
|
||||
candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnPlay")));
|
||||
candidates = candidates.concat(Array.from(container.querySelectorAll(".btnResume")));
|
||||
candidates = candidates.concat(Array.from(container.querySelectorAll(".btnPlay")));
|
||||
|
||||
var focusedElement;
|
||||
let focusedElement;
|
||||
|
||||
candidates.every(function (element) {
|
||||
if (focusManager.isCurrentlyFocusable(element)) {
|
||||
|
@ -79,7 +81,7 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager)
|
|||
|
||||
if (!focusedElement) {
|
||||
// FIXME: Multiple itemsContainers
|
||||
var itemsContainer = container.querySelector(".itemsContainer");
|
||||
const itemsContainer = container.querySelector(".itemsContainer");
|
||||
|
||||
if (itemsContainer) {
|
||||
focusedElement = focusManager.autoFocus(itemsContainer);
|
||||
|
@ -93,9 +95,8 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager)
|
|||
return focusedElement;
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
isEnabled: isEnabled,
|
||||
enable: enable,
|
||||
autoFocus: autoFocus
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1853,3 +1853,14 @@ import 'programStyles';
|
|||
cell.removeAttribute('data-seriestimerid');
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getCardsHtml: getCardsHtml,
|
||||
getDefaultBackgroundClass: getDefaultBackgroundClass,
|
||||
getDefaultText: getDefaultText,
|
||||
buildCards: buildCards,
|
||||
onUserDataChanged: onUserDataChanged,
|
||||
onTimerCreated: onTimerCreated,
|
||||
onTimerCancelled: onTimerCancelled,
|
||||
onSeriesTimerCancelled: onSeriesTimerCancelled
|
||||
};
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
function parentWithAttribute(elem, name, value) {
|
||||
/**
|
||||
* Useful DOM utilities.
|
||||
* @module components/dom
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns parent of element with specified attribute value.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {string} name - Attribute name.
|
||||
* @param {mixed} value - Attribute value.
|
||||
* @returns {HTMLElement} Parent with specified attribute value.
|
||||
*/
|
||||
export function parentWithAttribute(elem, name, value) {
|
||||
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
|
@ -14,8 +24,13 @@ define([], function () {
|
|||
return elem;
|
||||
}
|
||||
|
||||
function parentWithTag(elem, tagNames) {
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified tag names.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {(string|Array)} tagNames - Tag name or array of tag names.
|
||||
* @returns {HTMLElement} Parent with one of specified tag names.
|
||||
*/
|
||||
export function parentWithTag(elem, tagNames) {
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(tagNames)) {
|
||||
tagNames = [tagNames];
|
||||
|
@ -32,9 +47,14 @@ define([], function () {
|
|||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns _true_ if class list contains one of specified names.
|
||||
* @param {DOMTokenList} classList - Class list.
|
||||
* @param {Array} classNames - Array of class names.
|
||||
* @returns {boolean} _true_ if class list contains one of specified names.
|
||||
*/
|
||||
function containsAnyClass(classList, classNames) {
|
||||
|
||||
for (var i = 0, length = classNames.length; i < length; i++) {
|
||||
for (let i = 0, length = classNames.length; i < length; i++) {
|
||||
if (classList.contains(classNames[i])) {
|
||||
return true;
|
||||
}
|
||||
|
@ -42,8 +62,13 @@ define([], function () {
|
|||
return false;
|
||||
}
|
||||
|
||||
function parentWithClass(elem, classNames) {
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified class names.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {(string|Array)} classNames - Class name or array of class names.
|
||||
* @returns {HTMLElement} Parent with one of specified class names.
|
||||
*/
|
||||
export function parentWithClass(elem, classNames) {
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(classNames)) {
|
||||
classNames = [classNames];
|
||||
|
@ -60,9 +85,9 @@ define([], function () {
|
|||
return elem;
|
||||
}
|
||||
|
||||
var supportsCaptureOption = false;
|
||||
let supportsCaptureOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'capture', {
|
||||
const opts = Object.defineProperty({}, 'capture', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsCaptureOption = true;
|
||||
|
@ -73,29 +98,58 @@ define([], function () {
|
|||
console.debug('error checking capture support');
|
||||
}
|
||||
|
||||
function addEventListenerWithOptions(target, type, handler, options) {
|
||||
var optionsOrCapture = options || {};
|
||||
/**
|
||||
* Adds event listener to specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function addEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.addEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
function removeEventListenerWithOptions(target, type, handler, options) {
|
||||
var optionsOrCapture = options || {};
|
||||
/**
|
||||
* Removes event listener from specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function removeEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.removeEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
var windowSize;
|
||||
var windowSizeEventsBound;
|
||||
/**
|
||||
* Cached window size.
|
||||
*/
|
||||
let windowSize;
|
||||
|
||||
/**
|
||||
* Flag of event listener bound.
|
||||
*/
|
||||
let windowSizeEventsBound;
|
||||
|
||||
/**
|
||||
* Resets cached window size.
|
||||
*/
|
||||
function clearWindowSize() {
|
||||
windowSize = null;
|
||||
}
|
||||
|
||||
function getWindowSize() {
|
||||
/**
|
||||
* Returns window size.
|
||||
* @returns {Object} Window size.
|
||||
*/
|
||||
export function getWindowSize() {
|
||||
if (!windowSize) {
|
||||
windowSize = {
|
||||
innerHeight: window.innerHeight,
|
||||
|
@ -104,46 +158,60 @@ define([], function () {
|
|||
|
||||
if (!windowSizeEventsBound) {
|
||||
windowSizeEventsBound = true;
|
||||
addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { passive: true });
|
||||
addEventListenerWithOptions(window, 'resize', clearWindowSize, { passive: true });
|
||||
addEventListener(window, "orientationchange", clearWindowSize, { passive: true });
|
||||
addEventListener(window, 'resize', clearWindowSize, { passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
var standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
|
||||
function getScreenWidth() {
|
||||
var width = window.innerWidth;
|
||||
var height = window.innerHeight;
|
||||
/**
|
||||
* Standard screen widths.
|
||||
*/
|
||||
const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
|
||||
|
||||
/**
|
||||
* Returns screen width.
|
||||
* @returns {number} Screen width.
|
||||
*/
|
||||
export function getScreenWidth() {
|
||||
let width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
if (height > width) {
|
||||
width = height * (16.0 / 9.0);
|
||||
}
|
||||
|
||||
var closest = standardWidths.sort(function (a, b) {
|
||||
const closest = standardWidths.sort(function (a, b) {
|
||||
return Math.abs(width - a) - Math.abs(width - b);
|
||||
})[0];
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
var _animationEvent;
|
||||
function whichAnimationEvent() {
|
||||
/**
|
||||
* Name of animation end event.
|
||||
*/
|
||||
let _animationEvent;
|
||||
|
||||
/**
|
||||
* Returns name of animation end event.
|
||||
* @returns {string} Name of animation end event.
|
||||
*/
|
||||
export function whichAnimationEvent() {
|
||||
if (_animationEvent) {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
var t;
|
||||
var el = document.createElement("div");
|
||||
var animations = {
|
||||
const el = document.createElement("div");
|
||||
const animations = {
|
||||
"animation": "animationend",
|
||||
"OAnimation": "oAnimationEnd",
|
||||
"MozAnimation": "animationend",
|
||||
"WebkitAnimation": "webkitAnimationEnd"
|
||||
};
|
||||
for (t in animations) {
|
||||
for (let t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
|
@ -154,26 +222,36 @@ define([], function () {
|
|||
return _animationEvent;
|
||||
}
|
||||
|
||||
function whichAnimationCancelEvent() {
|
||||
|
||||
/**
|
||||
* Returns name of animation cancel event.
|
||||
* @returns {string} Name of animation cancel event.
|
||||
*/
|
||||
export function whichAnimationCancelEvent() {
|
||||
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
|
||||
}
|
||||
|
||||
var _transitionEvent;
|
||||
function whichTransitionEvent() {
|
||||
/**
|
||||
* Name of transition end event.
|
||||
*/
|
||||
let _transitionEvent;
|
||||
|
||||
/**
|
||||
* Returns name of transition end event.
|
||||
* @returns {string} Name of transition end event.
|
||||
*/
|
||||
export function whichTransitionEvent() {
|
||||
if (_transitionEvent) {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
var t;
|
||||
var el = document.createElement("div");
|
||||
var transitions = {
|
||||
const el = document.createElement("div");
|
||||
const transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
"MozTransition": "transitionend",
|
||||
"WebkitTransition": "webkitTransitionEnd"
|
||||
};
|
||||
for (t in transitions) {
|
||||
for (let t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
|
@ -184,16 +262,15 @@ define([], function () {
|
|||
return _transitionEvent;
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
parentWithAttribute: parentWithAttribute,
|
||||
parentWithClass: parentWithClass,
|
||||
parentWithTag: parentWithTag,
|
||||
addEventListener: addEventListenerWithOptions,
|
||||
removeEventListener: removeEventListenerWithOptions,
|
||||
addEventListener: addEventListener,
|
||||
removeEventListener: removeEventListener,
|
||||
getWindowSize: getWindowSize,
|
||||
getScreenWidth: getScreenWidth,
|
||||
whichTransitionEvent: whichTransitionEvent,
|
||||
whichAnimationEvent: whichAnimationEvent,
|
||||
whichAnimationCancelEvent: whichAnimationCancelEvent
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* Module for performing keyboard navigation.
|
||||
* @module components/input/keyboardnavigation
|
||||
*/
|
||||
|
||||
import inputManager from "inputManager";
|
||||
import layoutManager from "layoutManager";
|
||||
|
||||
|
@ -55,8 +60,8 @@ if (!hasFieldKey) {
|
|||
/**
|
||||
* Returns key name from event.
|
||||
*
|
||||
* @param {KeyboardEvent} event keyboard event
|
||||
* @return {string} key name
|
||||
* @param {KeyboardEvent} event - Keyboard event.
|
||||
* @return {string} Key name.
|
||||
*/
|
||||
export function getKeyName(event) {
|
||||
return KeyNames[event.keyCode] || event.key;
|
||||
|
@ -65,8 +70,8 @@ export function getKeyName(event) {
|
|||
/**
|
||||
* Returns _true_ if key is used for navigation.
|
||||
*
|
||||
* @param {string} key name
|
||||
* @return {boolean} _true_ if key is used for navigation
|
||||
* @param {string} key - Key name.
|
||||
* @return {boolean} _true_ if key is used for navigation.
|
||||
*/
|
||||
export function isNavigationKey(key) {
|
||||
return NavigationKeys.indexOf(key) != -1;
|
||||
|
@ -155,3 +160,9 @@ function attachGamepadScript(e) {
|
|||
|
||||
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
|
||||
window.addEventListener("gamepadconnected", attachGamepadScript);
|
||||
|
||||
export default {
|
||||
enable: enable,
|
||||
getKeyName: getKeyName,
|
||||
isNavigationKey: isNavigationKey
|
||||
};
|
||||
|
|
|
@ -1,38 +1,46 @@
|
|||
define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManager) {
|
||||
"use strict";
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for controlling scroll behavior.
|
||||
* @module components/scrollManager
|
||||
*/
|
||||
|
||||
import dom from "dom";
|
||||
import browser from "browser";
|
||||
import layoutManager from "layoutManager";
|
||||
|
||||
/**
|
||||
* Scroll time in ms.
|
||||
*/
|
||||
var ScrollTime = 270;
|
||||
const ScrollTime = 270;
|
||||
|
||||
/**
|
||||
* Epsilon for comparing values.
|
||||
*/
|
||||
var Epsilon = 1e-6;
|
||||
const Epsilon = 1e-6;
|
||||
|
||||
// FIXME: Need to scroll to top of page to fully show the top menu. This can be solved by some marker of top most elements or their containers
|
||||
/**
|
||||
* Returns minimum vertical scroll.
|
||||
* Scroll less than that value will be zeroed.
|
||||
*
|
||||
* @return {number} minimum vertical scroll
|
||||
* @return {number} Minimum vertical scroll.
|
||||
*/
|
||||
function minimumScrollY() {
|
||||
var topMenu = document.querySelector(".headerTop");
|
||||
const topMenu = document.querySelector(".headerTop");
|
||||
if (topMenu) {
|
||||
return topMenu.clientHeight;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var supportsSmoothScroll = "scrollBehavior" in document.documentElement.style;
|
||||
const supportsSmoothScroll = "scrollBehavior" in document.documentElement.style;
|
||||
|
||||
var supportsScrollToOptions = false;
|
||||
let supportsScrollToOptions = false;
|
||||
try {
|
||||
var elem = document.createElement("div");
|
||||
const elem = document.createElement("div");
|
||||
|
||||
var opts = Object.defineProperty({}, "behavior", {
|
||||
const opts = Object.defineProperty({}, "behavior", {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsScrollToOptions = true;
|
||||
|
@ -47,10 +55,10 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Returns value clamped by range [min, max].
|
||||
*
|
||||
* @param {number} value clamped value
|
||||
* @param {number} min begining of range
|
||||
* @param {number} max ending of range
|
||||
* @return {number} clamped value
|
||||
* @param {number} value - Clamped value.
|
||||
* @param {number} min - Begining of range.
|
||||
* @param {number} max - Ending of range.
|
||||
* @return {number} Clamped value.
|
||||
*/
|
||||
function clamp(value, min, max) {
|
||||
return value <= min ? min : value >= max ? max : value;
|
||||
|
@ -60,15 +68,15 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
* Returns the required delta to fit range 1 into range 2.
|
||||
* In case of range 1 is bigger than range 2 returns delta to fit most out of range part.
|
||||
*
|
||||
* @param {number} begin1 begining of range 1
|
||||
* @param {number} end1 ending of range 1
|
||||
* @param {number} begin2 begining of range 2
|
||||
* @param {number} end2 ending of range 2
|
||||
* @return {number} delta: <0 move range1 to the left, >0 - to the right
|
||||
* @param {number} begin1 - Begining of range 1.
|
||||
* @param {number} end1 - Ending of range 1.
|
||||
* @param {number} begin2 - Begining of range 2.
|
||||
* @param {number} end2 - Ending of range 2.
|
||||
* @return {number} Delta: <0 move range1 to the left, >0 - to the right.
|
||||
*/
|
||||
function fitRange(begin1, end1, begin2, end2) {
|
||||
var delta1 = begin1 - begin2;
|
||||
var delta2 = end2 - end1;
|
||||
const delta1 = begin1 - begin2;
|
||||
const delta2 = end2 - end1;
|
||||
if (delta1 < 0 && delta1 < delta2) {
|
||||
return -delta1;
|
||||
} else if (delta2 < 0) {
|
||||
|
@ -80,13 +88,21 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Ease value.
|
||||
*
|
||||
* @param {number} t value in range [0, 1]
|
||||
* @return {number} eased value in range [0, 1]
|
||||
* @param {number} t - Value in range [0, 1].
|
||||
* @return {number} Eased value in range [0, 1].
|
||||
*/
|
||||
function ease(t) {
|
||||
return t*(2 - t); // easeOutQuad === ease-out
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Rect
|
||||
* @property {number} left - X coordinate of top-left corner.
|
||||
* @property {number} top - Y coordinate of top-left corner.
|
||||
* @property {number} width - Width.
|
||||
* @property {number} height - Height.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Document scroll wrapper helps to unify scrolling and fix issues of some browsers.
|
||||
*
|
||||
|
@ -100,41 +116,68 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
*
|
||||
* Tizen 5 Browser/Native: scrolls documentElement (and window); has a document.scrollingElement
|
||||
*/
|
||||
function DocumentScroller() {
|
||||
}
|
||||
|
||||
DocumentScroller.prototype = {
|
||||
class DocumentScroller {
|
||||
/**
|
||||
* Horizontal scroll position.
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollLeft() {
|
||||
return window.pageXOffset;
|
||||
},
|
||||
}
|
||||
|
||||
set scrollLeft(val) {
|
||||
window.scroll(val, window.pageYOffset);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertical scroll position.
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollTop() {
|
||||
return window.pageYOffset;
|
||||
},
|
||||
}
|
||||
|
||||
set scrollTop(val) {
|
||||
window.scroll(window.pageXOffset, val);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Horizontal scroll size (scroll width).
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollWidth() {
|
||||
return Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertical scroll size (scroll height).
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollHeight() {
|
||||
return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Horizontal client size (client width).
|
||||
* @type {number}
|
||||
*/
|
||||
get clientWidth() {
|
||||
return Math.min(document.documentElement.clientWidth, document.body.clientWidth);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertical client size (client height).
|
||||
* @type {number}
|
||||
*/
|
||||
get clientHeight() {
|
||||
return Math.min(document.documentElement.clientHeight, document.body.clientHeight);
|
||||
},
|
||||
}
|
||||
|
||||
getBoundingClientRect: function() {
|
||||
/**
|
||||
* Returns bounding client rect.
|
||||
* @return {Rect} Bounding client rect.
|
||||
*/
|
||||
getBoundingClientRect() {
|
||||
// Make valid viewport coordinates: documentElement.getBoundingClientRect returns rect of entire document relative to viewport
|
||||
return {
|
||||
left: 0,
|
||||
|
@ -142,26 +185,34 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
width: this.clientWidth,
|
||||
height: this.clientHeight
|
||||
};
|
||||
},
|
||||
|
||||
scrollTo: function() {
|
||||
window.scrollTo.apply(window, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
var documentScroller = new DocumentScroller();
|
||||
|
||||
/**
|
||||
* Returns parent element that can be scrolled. If no such, returns documentElement.
|
||||
* Scrolls window.
|
||||
* @param {...mixed} args See window.scrollTo.
|
||||
*/
|
||||
scrollTo() {
|
||||
window.scrollTo.apply(window, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default (document) scroller.
|
||||
*/
|
||||
const documentScroller = new DocumentScroller();
|
||||
|
||||
/**
|
||||
* Returns parent element that can be scrolled. If no such, returns document scroller.
|
||||
*
|
||||
* @param {HTMLElement} element element for which parent is being searched
|
||||
* @param {boolean} vertical search for vertical scrollable parent
|
||||
* @param {HTMLElement} element - Element for which parent is being searched.
|
||||
* @param {boolean} vertical - Search for vertical scrollable parent.
|
||||
* @param {HTMLElement|DocumentScroller} Parent element that can be scrolled or document scroller.
|
||||
*/
|
||||
function getScrollableParent(element, vertical) {
|
||||
if (element) {
|
||||
var nameScroll = "scrollWidth";
|
||||
var nameClient = "clientWidth";
|
||||
var nameClass = "scrollX";
|
||||
let nameScroll = "scrollWidth";
|
||||
let nameClient = "clientWidth";
|
||||
let nameClass = "scrollX";
|
||||
|
||||
if (vertical) {
|
||||
nameScroll = "scrollHeight";
|
||||
|
@ -169,7 +220,7 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
nameClass = "scrollY";
|
||||
}
|
||||
|
||||
var parent = element.parentElement;
|
||||
let parent = element.parentElement;
|
||||
|
||||
while (parent) {
|
||||
// Skip 'emby-scroller' because it scrolls by itself
|
||||
|
@ -187,20 +238,20 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
|
||||
/**
|
||||
* @typedef {Object} ScrollerData
|
||||
* @property {number} scrollPos current scroll position
|
||||
* @property {number} scrollSize scroll size
|
||||
* @property {number} clientSize client size
|
||||
* @property {number} scrollPos - Current scroll position.
|
||||
* @property {number} scrollSize - Scroll size.
|
||||
* @property {number} clientSize - Client size.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns scroll data for specified orientation.
|
||||
* Returns scroller data for specified orientation.
|
||||
*
|
||||
* @param {HTMLElement} scroller scroller
|
||||
* @param {boolean} vertical vertical scroll data
|
||||
* @return {ScrollerData} scroll data
|
||||
* @param {HTMLElement} scroller - Scroller.
|
||||
* @param {boolean} vertical - Vertical scroller data.
|
||||
* @return {ScrollerData} Scroller data.
|
||||
*/
|
||||
function getScrollerData(scroller, vertical) {
|
||||
var data = {};
|
||||
let data = {};
|
||||
|
||||
if (!vertical) {
|
||||
data.scrollPos = scroller.scrollLeft;
|
||||
|
@ -218,14 +269,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Returns position of child of scroller for specified orientation.
|
||||
*
|
||||
* @param {HTMLElement} scroller scroller
|
||||
* @param {HTMLElement} element child of scroller
|
||||
* @param {boolean} vertical vertical scroll
|
||||
* @return {number} child position
|
||||
* @param {HTMLElement} scroller - Scroller.
|
||||
* @param {HTMLElement} element - Child of scroller.
|
||||
* @param {boolean} vertical - Vertical scroll.
|
||||
* @return {number} Child position.
|
||||
*/
|
||||
function getScrollerChildPos(scroller, element, vertical) {
|
||||
var elementRect = element.getBoundingClientRect();
|
||||
var scrollerRect = scroller.getBoundingClientRect();
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
const scrollerRect = scroller.getBoundingClientRect();
|
||||
|
||||
if (!vertical) {
|
||||
return scroller.scrollLeft + elementRect.left - scrollerRect.left;
|
||||
|
@ -237,21 +288,21 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Returns scroll position for element.
|
||||
*
|
||||
* @param {ScrollerData} scrollerData scroller data
|
||||
* @param {number} elementPos child element position
|
||||
* @param {number} elementSize child element size
|
||||
* @param {boolean} centered scroll to center
|
||||
* @return {number} scroll position
|
||||
* @param {ScrollerData} scrollerData - Scroller data.
|
||||
* @param {number} elementPos - Child element position.
|
||||
* @param {number} elementSize - Child element size.
|
||||
* @param {boolean} centered - Scroll to center.
|
||||
* @return {number} Scroll position.
|
||||
*/
|
||||
function calcScroll(scrollerData, elementPos, elementSize, centered) {
|
||||
var maxScroll = scrollerData.scrollSize - scrollerData.clientSize;
|
||||
const maxScroll = scrollerData.scrollSize - scrollerData.clientSize;
|
||||
|
||||
var scroll;
|
||||
let scroll;
|
||||
|
||||
if (centered) {
|
||||
scroll = elementPos + (elementSize - scrollerData.clientSize) / 2;
|
||||
} else {
|
||||
var delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1);
|
||||
const delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1);
|
||||
scroll = scrollerData.scrollPos - delta;
|
||||
}
|
||||
|
||||
|
@ -261,14 +312,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Calls scrollTo function in proper way.
|
||||
*
|
||||
* @param {HTMLElement} scroller scroller
|
||||
* @param {ScrollToOptions} options scroll options
|
||||
* @param {HTMLElement} scroller - Scroller.
|
||||
* @param {ScrollToOptions} options - Scroll options.
|
||||
*/
|
||||
function scrollToHelper(scroller, options) {
|
||||
if ("scrollTo" in scroller) {
|
||||
if (!supportsScrollToOptions) {
|
||||
var scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft);
|
||||
var scrollY = (options.top !== undefined ? options.top : scroller.scrollTop);
|
||||
const scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft);
|
||||
const scrollY = (options.top !== undefined ? options.top : scroller.scrollTop);
|
||||
scroller.scrollTo(scrollX, scrollY);
|
||||
} else {
|
||||
scroller.scrollTo(options);
|
||||
|
@ -286,14 +337,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Performs built-in scroll.
|
||||
*
|
||||
* @param {HTMLElement} xScroller horizontal scroller
|
||||
* @param {number} scrollX horizontal coordinate
|
||||
* @param {HTMLElement} yScroller vertical scroller
|
||||
* @param {number} scrollY vertical coordinate
|
||||
* @param {boolean} smooth smooth scrolling
|
||||
* @param {HTMLElement} xScroller - Horizontal scroller.
|
||||
* @param {number} scrollX - Horizontal coordinate.
|
||||
* @param {HTMLElement} yScroller - Vertical scroller.
|
||||
* @param {number} scrollY - Vertical coordinate.
|
||||
* @param {boolean} smooth - Smooth scrolling.
|
||||
*/
|
||||
function builtinScroll(xScroller, scrollX, yScroller, scrollY, smooth) {
|
||||
var scrollBehavior = smooth ? "smooth" : "instant";
|
||||
const scrollBehavior = smooth ? "smooth" : "instant";
|
||||
|
||||
if (xScroller !== yScroller) {
|
||||
scrollToHelper(xScroller, {left: scrollX, behavior: scrollBehavior});
|
||||
|
@ -303,7 +354,10 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
}
|
||||
}
|
||||
|
||||
var scrollTimer;
|
||||
/**
|
||||
* Requested frame for animated scroll.
|
||||
*/
|
||||
let scrollTimer;
|
||||
|
||||
/**
|
||||
* Resets scroll timer to stop scrolling.
|
||||
|
@ -316,29 +370,29 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Performs animated scroll.
|
||||
*
|
||||
* @param {HTMLElement} xScroller horizontal scroller
|
||||
* @param {number} scrollX horizontal coordinate
|
||||
* @param {HTMLElement} yScroller vertical scroller
|
||||
* @param {number} scrollY vertical coordinate
|
||||
* @param {HTMLElement} xScroller - Horizontal scroller.
|
||||
* @param {number} scrollX - Horizontal coordinate.
|
||||
* @param {HTMLElement} yScroller - Vertical scroller.
|
||||
* @param {number} scrollY - Vertical coordinate.
|
||||
*/
|
||||
function animateScroll(xScroller, scrollX, yScroller, scrollY) {
|
||||
|
||||
var ox = xScroller.scrollLeft;
|
||||
var oy = yScroller.scrollTop;
|
||||
var dx = scrollX - ox;
|
||||
var dy = scrollY - oy;
|
||||
const ox = xScroller.scrollLeft;
|
||||
const oy = yScroller.scrollTop;
|
||||
const dx = scrollX - ox;
|
||||
const dy = scrollY - oy;
|
||||
|
||||
if (Math.abs(dx) < Epsilon && Math.abs(dy) < Epsilon) {
|
||||
return;
|
||||
}
|
||||
|
||||
var start;
|
||||
let start;
|
||||
|
||||
function scrollAnim(currentTimestamp) {
|
||||
|
||||
start = start || currentTimestamp;
|
||||
|
||||
var k = Math.min(1, (currentTimestamp - start) / ScrollTime);
|
||||
let k = Math.min(1, (currentTimestamp - start) / ScrollTime);
|
||||
|
||||
if (k === 1) {
|
||||
resetScrollTimer();
|
||||
|
@ -348,8 +402,8 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
|
||||
k = ease(k);
|
||||
|
||||
var x = ox + dx*k;
|
||||
var y = oy + dy*k;
|
||||
const x = ox + dx*k;
|
||||
const y = oy + dy*k;
|
||||
|
||||
builtinScroll(xScroller, x, yScroller, y, false);
|
||||
|
||||
|
@ -362,11 +416,11 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Performs scroll.
|
||||
*
|
||||
* @param {HTMLElement} xScroller horizontal scroller
|
||||
* @param {number} scrollX horizontal coordinate
|
||||
* @param {HTMLElement} yScroller vertical scroller
|
||||
* @param {number} scrollY vertical coordinate
|
||||
* @param {boolean} smooth smooth scrolling
|
||||
* @param {HTMLElement} xScroller - Horizontal scroller.
|
||||
* @param {number} scrollX - Horizontal coordinate.
|
||||
* @param {HTMLElement} yScroller - Vertical scroller.
|
||||
* @param {number} scrollY - Vertical coordinate.
|
||||
* @param {boolean} smooth - Smooth scrolling.
|
||||
*/
|
||||
function doScroll(xScroller, scrollX, yScroller, scrollY, smooth) {
|
||||
|
||||
|
@ -403,26 +457,26 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Returns true if scroll manager is enabled.
|
||||
*/
|
||||
var isEnabled = function() {
|
||||
export function isEnabled() {
|
||||
return layoutManager.tv;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the document to a given position.
|
||||
*
|
||||
* @param {number} scrollX horizontal coordinate
|
||||
* @param {number} scrollY vertical coordinate
|
||||
* @param {boolean} [smooth=false] smooth scrolling
|
||||
* @param {number} scrollX - Horizontal coordinate.
|
||||
* @param {number} scrollY - Vertical coordinate.
|
||||
* @param {boolean} [smooth=false] - Smooth scrolling.
|
||||
*/
|
||||
var scrollTo = function(scrollX, scrollY, smooth) {
|
||||
export function scrollTo(scrollX, scrollY, smooth) {
|
||||
|
||||
smooth = !!smooth;
|
||||
|
||||
// Scroller is document itself by default
|
||||
var scroller = getScrollableParent(null, false);
|
||||
const scroller = getScrollableParent(null, false);
|
||||
|
||||
var xScrollerData = getScrollerData(scroller, false);
|
||||
var yScrollerData = getScrollerData(scroller, true);
|
||||
const xScrollerData = getScrollerData(scroller, false);
|
||||
const yScrollerData = getScrollerData(scroller, true);
|
||||
|
||||
scrollX = clamp(Math.round(scrollX), 0, xScrollerData.scrollSize - xScrollerData.clientSize);
|
||||
scrollY = clamp(Math.round(scrollY), 0, yScrollerData.scrollSize - yScrollerData.clientSize);
|
||||
|
@ -433,39 +487,39 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
/**
|
||||
* Scrolls the document to a given element.
|
||||
*
|
||||
* @param {HTMLElement} element target element of scroll task
|
||||
* @param {boolean} [smooth=false] smooth scrolling
|
||||
* @param {HTMLElement} element - Target element of scroll task.
|
||||
* @param {boolean} [smooth=false] - Smooth scrolling.
|
||||
*/
|
||||
var scrollToElement = function(element, smooth) {
|
||||
export function scrollToElement(element, smooth) {
|
||||
|
||||
smooth = !!smooth;
|
||||
|
||||
var scrollCenterX = true;
|
||||
var scrollCenterY = true;
|
||||
let scrollCenterX = true;
|
||||
let scrollCenterY = true;
|
||||
|
||||
var offsetParent = element.offsetParent;
|
||||
const offsetParent = element.offsetParent;
|
||||
|
||||
// In Firefox offsetParent.offsetParent is BODY
|
||||
var isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === "fixed");
|
||||
const isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === "fixed");
|
||||
|
||||
// Scroll fixed elements to nearest edge (or do not scroll at all)
|
||||
if (isFixed) {
|
||||
scrollCenterX = scrollCenterY = false;
|
||||
}
|
||||
|
||||
var xScroller = getScrollableParent(element, false);
|
||||
var yScroller = getScrollableParent(element, true);
|
||||
const xScroller = getScrollableParent(element, false);
|
||||
const yScroller = getScrollableParent(element, true);
|
||||
|
||||
var elementRect = element.getBoundingClientRect();
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
|
||||
var xScrollerData = getScrollerData(xScroller, false);
|
||||
var yScrollerData = getScrollerData(yScroller, true);
|
||||
const xScrollerData = getScrollerData(xScroller, false);
|
||||
const yScrollerData = getScrollerData(yScroller, true);
|
||||
|
||||
var xPos = getScrollerChildPos(xScroller, element, false);
|
||||
var yPos = getScrollerChildPos(yScroller, element, true);
|
||||
const xPos = getScrollerChildPos(xScroller, element, false);
|
||||
const yPos = getScrollerChildPos(yScroller, element, true);
|
||||
|
||||
var scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX);
|
||||
var scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY);
|
||||
const scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX);
|
||||
let scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY);
|
||||
|
||||
// HACK: Scroll to top for top menu because it is hidden
|
||||
// FIXME: Need a marker to scroll top/bottom
|
||||
|
@ -490,9 +544,8 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
|
|||
}, {capture: true});
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
isEnabled: isEnabled,
|
||||
scrollTo: scrollTo,
|
||||
scrollToElement: scrollToElement
|
||||
};
|
||||
});
|
||||
|
|
|
@ -433,14 +433,10 @@ define(['browser'], function (browser) {
|
|||
|
||||
var supportsDts = browser.tizen || browser.orsay || browser.web0s || options.supportsDts;
|
||||
|
||||
if (self.tizen && self.tizen.systeminfo) {
|
||||
var v = tizen.systeminfo.getCapability('http://tizen.org/feature/platform.version');
|
||||
|
||||
// DTS audio not supported in 2018 models (Tizen 4.0)
|
||||
if (v && parseFloat(v) >= parseFloat('4.0')) {
|
||||
if (browser.tizenVersion >= 4) {
|
||||
supportsDts = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsDts) {
|
||||
videoAudioCodecs.push('dca');
|
||||
|
@ -766,6 +762,11 @@ define(['browser'], function (browser) {
|
|||
maxH264Level = 51;
|
||||
}
|
||||
|
||||
// Support H264 Level 52 (Tizen 5.0) - app only
|
||||
if (browser.tizenVersion >= 5 && window.NativeShell) {
|
||||
maxH264Level = 52;
|
||||
}
|
||||
|
||||
if (browser.tizen || browser.orsay ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"All": "Всички",
|
||||
"AllLibraries": "Всички библиотеки",
|
||||
"Art": "Картина",
|
||||
"Artists": "Изпълнители",
|
||||
"Artists": "Артисти",
|
||||
"AttributeNew": "Нови",
|
||||
"Audio": "Звук",
|
||||
"Auto": "Автоматично",
|
||||
|
@ -839,5 +839,7 @@
|
|||
"LabelKodiMetadataSaveImagePathsHelp": "Препоръчително е ако имате изображения, пътят към които не е съобразен с изискванията на Коди.",
|
||||
"LabelKodiMetadataSaveImagePaths": "Записване на пътеките към изображенията в nfo файловете",
|
||||
"LabelChannels": "Канали:",
|
||||
"DropShadow": "Сянка"
|
||||
"DropShadow": "Сянка",
|
||||
"Raised": "Повишено",
|
||||
"OptionResElement": "рес. елемент"
|
||||
}
|
||||
|
|
|
@ -1401,7 +1401,7 @@
|
|||
"TitleSupport": "Hilfe",
|
||||
"Whitelist": "Erlaubt",
|
||||
"AuthProviderHelp": "Auswählen eines Authentifizierungsanbieter, der zur Authentifizierung des Passworts dieses Benutzes verwendet werden soll.",
|
||||
"Features": "Features",
|
||||
"Features": "Funktionen",
|
||||
"HeaderFavoriteBooks": "Lieblingsbücher",
|
||||
"HeaderFavoriteMovies": "Lieblingsfilme",
|
||||
"HeaderFavoriteShows": "Lieblingsserien",
|
||||
|
|
|
@ -224,5 +224,96 @@
|
|||
"AddedOnValue": "{0} افزوده شد",
|
||||
"AddToPlaylist": "افزودن به لیست پخش",
|
||||
"AddToPlayQueue": "افزودن به صف پخش",
|
||||
"AddToCollection": "افزودن به مجموعه"
|
||||
"AddToCollection": "افزودن به مجموعه",
|
||||
"ExitFullscreen": "خروج از تمام صفحه",
|
||||
"EveryNDays": "هر {0} روز",
|
||||
"ErrorMessageStartHourGreaterThanEnd": "زمان پایان باید پس از زمان شروع باشد.",
|
||||
"Episodes": "قسمتها",
|
||||
"EndsAtValue": "تمام شده در {0}",
|
||||
"Ended": "تمام شده",
|
||||
"EnableThemeVideos": "تم فیلمها",
|
||||
"EnableThemeSongs": "آهنگهای تم",
|
||||
"EnableStreamLooping": "چرخش خودکار پخشهای زنده",
|
||||
"EnablePhotos": "نمایش عکسها",
|
||||
"EnableNextVideoInfoOverlay": "نمایش اطلاعات ودیوی بعدی حین پخش ویدیو",
|
||||
"EnableHardwareEncoding": "فعال سازی رمزگذاری سخت افزاری",
|
||||
"EnableExternalVideoPlayersHelp": "یک منوی پخش کننده ویدیوی خارجی، زمانی که شروع به پخش ویدیو میشود نمایش داده خواهد شد.",
|
||||
"EnableExternalVideoPlayers": "پخش کننده ویدیوی خارجی",
|
||||
"EnableDisplayMirroring": "نمایش حالت آینه",
|
||||
"EnableCinemaMode": "حالت سینما",
|
||||
"EnableBackdrops": "پشتزمینهها",
|
||||
"EditSubtitles": "ویرایش زیرنویسها",
|
||||
"EditMetadata": "ویرایش ابرداده",
|
||||
"EditImages": "ویرایش عکسها",
|
||||
"Edit": "ویرایش",
|
||||
"DropShadow": "سایه پشت زمینه",
|
||||
"DrmChannelsNotImported": "کانالها با DRM وارد نخواند شد.",
|
||||
"DownloadsValue": "{0} بارگیریها",
|
||||
"Download": "بارگیری",
|
||||
"Down": "پایین",
|
||||
"DoNotRecord": "ضبط نکن",
|
||||
"DisplayModeHelp": "نوع صفحه نمایشی که Jellyfin را اجرا میکنید را انتخاب کنید.",
|
||||
"DisplayMissingEpisodesWithinSeasons": "قسمتهای ناموجود در فصلها را نمایش بده",
|
||||
"DisplayInMyMedia": "نمایش در صفحهی خانه",
|
||||
"Display": "نمایش",
|
||||
"Dislike": "دوست نداشتن",
|
||||
"Disconnect": "قطع اتصال",
|
||||
"Disc": "دیسک",
|
||||
"Directors": "کارگردانان",
|
||||
"Director": "کارگردان",
|
||||
"DirectStreaming": "پخش مستقیم",
|
||||
"DirectStreamHelp2": "پخش مستقیم فایل از قدرت پردازش بسیار کمی بدون از دست دادن کیفیت ویدیو استفاده میکند.",
|
||||
"DirectPlaying": "پخش مستقیم",
|
||||
"DetectingDevices": "در حال تشخیص دستگاهها",
|
||||
"Descending": "پایین رونده",
|
||||
"Depressed": "پژمرده",
|
||||
"DeleteUserConfirmation": "آیا اطمینان دارید که میخواهید این کاربر را حذف کنید؟",
|
||||
"DeleteUser": "حذف کاربر",
|
||||
"DeleteImageConfirmation": "آیا اطمینان دارید که میخواهید این تصویر را حذف کنید؟",
|
||||
"DeleteImage": "حذف تصویر",
|
||||
"DeleteDeviceConfirmation": "آیا از حذف این دستگاه اطمینان دارید؟ هنگامی که یک کاربر دوباره با آن دستگاه وارد شود، دوباره نمایش داده میشود.",
|
||||
"Delete": "حذف",
|
||||
"DefaultMetadataLangaugeDescription": "این موارد پیشفرضهای شماست و میتوانید برای هر کتابخانه آن را شخصی سازی کنید.",
|
||||
"DefaultErrorMessage": "خطایی در پردازش درخواست رخ داد. لطفا اندکی بعد دوباره تلاش کنید.",
|
||||
"Default": "پیشفرض",
|
||||
"DeathDateValue": "تلف شد: {0}",
|
||||
"DatePlayed": "تاریخ پخش شده",
|
||||
"DateAdded": "تاریخ اضافه شده",
|
||||
"CriticRating": "امتیاز منتقدان",
|
||||
"CopyStreamURLError": "در کپی کردن آدرس خطایی رخ داد.",
|
||||
"CopyStreamURLSuccess": "آدرس با موفقیت کپی شد.",
|
||||
"CopyStreamURL": "کپی آدرس پخش",
|
||||
"Continuing": "ادامه",
|
||||
"ContinueWatching": "ادامه تماشا",
|
||||
"Connect": "اتصال",
|
||||
"ConfirmEndPlayerSession": "آیا میخواهید Jellyfin را روی {0} خاموش کنید؟",
|
||||
"ConfirmDeletion": "تایید حذف",
|
||||
"ConfirmDeleteImage": "حذف تصویر؟",
|
||||
"Composer": "آهنگساز",
|
||||
"CommunityRating": "امتیاز عمومی",
|
||||
"ColorTransfer": "انتقال رنگ",
|
||||
"ColorSpace": "فضای رنگی",
|
||||
"ColorPrimaries": "مقدمات رنگی",
|
||||
"ClientSettings": "تنظیمات مشتری",
|
||||
"ChannelNumber": "شماره کانال",
|
||||
"ChannelNameOnly": "تنها کانال {0}",
|
||||
"Categories": "دستهبندیها",
|
||||
"CancelSeries": "لغو سریالها",
|
||||
"CancelRecording": "لغو ضبط",
|
||||
"ButtonWebsite": "وبسایت",
|
||||
"ButtonViewWebsite": "بازدید وبسایت",
|
||||
"ButtonUp": "بالا",
|
||||
"ButtonUninstall": "حذف نصب",
|
||||
"ButtonTrailer": "تریلر",
|
||||
"ButtonSubtitles": "زیرنویسها",
|
||||
"ButtonSubmit": "تایید",
|
||||
"ButtonSplit": "جدا کردن",
|
||||
"ButtonStop": "توقف",
|
||||
"ButtonStart": "شروع",
|
||||
"ButtonSignIn": "ورود",
|
||||
"ButtonShutdown": "خاموش",
|
||||
"ButtonSelectDirectory": "انتخاب مسیر",
|
||||
"ButtonEditOtherUserPreferences": "نمایه، تصویر و ترجیحات شخصی این کاربر را ویرایش کنید.",
|
||||
"BrowsePluginCatalogMessage": "برای مرور کردن افزونههای موجود، به فروشگاه افزونههای ما سر بزنید.",
|
||||
"AuthProviderHelp": "ارائه دهنده تأیید اعتبار را انتخاب کنید تا برای تأیید اعتبار گذرواژه این کاربر استفاده شود."
|
||||
}
|
||||
|
|
|
@ -1446,7 +1446,7 @@
|
|||
"LabelAudioChannels": "Canaux audio :",
|
||||
"HeaderFavoriteBooks": "Livres préférés",
|
||||
"FetchingData": "Récuperer des données suplémentaires",
|
||||
"CopyStreamURLSuccess": "URL copiée avec succès",
|
||||
"CopyStreamURLSuccess": "URL copiée avec succès.",
|
||||
"CopyStreamURL": "Copier l'URL du flux",
|
||||
"LabelBaseUrlHelp": "Vous pouvez ajouter un sous-répertoire personalisé ici pour accéder au serveur depuis une URL plus exclusive.",
|
||||
"HeaderFavoritePeople": "Personnes préférées",
|
||||
|
|
|
@ -264,7 +264,7 @@
|
|||
"HeaderAddUser": "Aggiungi utente",
|
||||
"HeaderAdditionalParts": "Parti addizionali",
|
||||
"HeaderAdmin": "Admin",
|
||||
"HeaderAlbumArtists": "Artisti dell' Album",
|
||||
"HeaderAlbumArtists": "Artisti degli Album",
|
||||
"HeaderAlbums": "Album",
|
||||
"HeaderAlert": "Avviso",
|
||||
"HeaderAllowMediaDeletionFrom": "Abilita Eliminazione Media Da",
|
||||
|
@ -572,7 +572,7 @@
|
|||
"LabelEvent": "Evento:",
|
||||
"LabelEveryXMinutes": "Tutti:",
|
||||
"LabelExtractChaptersDuringLibraryScan": "Estrarre immagini capitolo durante la scansione della libreria",
|
||||
"LabelExtractChaptersDuringLibraryScanHelp": "Genera le immagini del capitolo quando i video vengono importati durante la scansione della libreria. Altrimenti verranno estratti durante l'operazione pianificata di estrazione delle immagini capitolo, permettendo la scansione della libreria più velocemente.",
|
||||
"LabelExtractChaptersDuringLibraryScanHelp": "Genera le immagini capitolo quando i video vengono importati durante la scansione della libreria. Alternativamente, verranno estratti durante l'operazione pianificata di estrazione delle immagini capitolo, permettendo la scansione della libreria più velocemente.",
|
||||
"LabelFailed": "Fallito",
|
||||
"LabelFileOrUrl": "File o URL:",
|
||||
"LabelFinish": "Finito",
|
||||
|
@ -947,8 +947,8 @@
|
|||
"OptionCustomUsers": "Personalizza",
|
||||
"OptionDaily": "Giornaliero",
|
||||
"OptionDateAdded": "Aggiunto il",
|
||||
"OptionDateAddedFileTime": "Utilizzare file di data di creazione",
|
||||
"OptionDateAddedImportTime": "Utilizza la data scansionato in biblioteca",
|
||||
"OptionDateAddedFileTime": "Utilizzare la data di creazione del file",
|
||||
"OptionDateAddedImportTime": "Utilizza la data di scansione nella libreria",
|
||||
"OptionDatePlayed": "Visto il",
|
||||
"OptionDescending": "Decrescente",
|
||||
"OptionDisableUser": "Disabilita questo utente",
|
||||
|
@ -1076,7 +1076,7 @@
|
|||
"Programs": "Programmi",
|
||||
"Quality": "Qualità",
|
||||
"QueueAllFromHere": "In coda tutto da qui in poi",
|
||||
"Raised": "Sospeso",
|
||||
"Raised": "Rilievo",
|
||||
"Rate": "Vota",
|
||||
"RecentlyWatched": "Visti di recente",
|
||||
"RecommendationBecauseYouLike": "Perché ti piace {0}",
|
||||
|
@ -1168,7 +1168,7 @@
|
|||
"SystemDlnaProfilesHelp": "I profili di sistema sono in sola lettura. Le modifiche ad un profilo di sistema verranno salvate in un nuovo profilo personalizzato.",
|
||||
"TabAccess": "Accesso",
|
||||
"TabAdvanced": "Avanzato",
|
||||
"TabAlbumArtists": "Artisti degli album",
|
||||
"TabAlbumArtists": "Artisti degli Album",
|
||||
"TabAlbums": "Album",
|
||||
"TabArtists": "Artisti",
|
||||
"TabCatalog": "Catalogo",
|
||||
|
@ -1312,7 +1312,7 @@
|
|||
"HeaderFavoriteArtists": "Artisti Preferiti",
|
||||
"HeaderFavoriteSongs": "Brani Preferiti",
|
||||
"HeaderFavoriteVideos": "Video Preferiti",
|
||||
"HeaderFetcherSettings": "Impostazioni Fetcher",
|
||||
"HeaderFetcherSettings": "Impostazioni del Fetcher",
|
||||
"HeaderImageOptions": "Opzioni Immagine",
|
||||
"HeaderRestartingServer": "Riavvio Server",
|
||||
"Home": "Home",
|
||||
|
@ -1467,5 +1467,8 @@
|
|||
"LabelCorruptedFrames": "Frame corrotti:",
|
||||
"AskAdminToCreateLibrary": "Chiedi ad un amministratore di creare una libreria.",
|
||||
"AllowFfmpegThrottlingHelp": "Quando una transcodifica o un remux sono abbastanza avanti rispetto alla corrente posizione di riproduzione, pausa il processo così da consumare meno risorse. Questo è utile quando si guarda un video senza avanzare spesso durante la riproduzione. Disattiva questa opzione se stai avendo problemi di riproduzione.",
|
||||
"AllowFfmpegThrottling": "Acceleratore Transcodifica"
|
||||
"AllowFfmpegThrottling": "Acceleratore Transcodifica",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNames": "Preferisci le informazioni incorporate nell'episodio rispetto ai nomi dei file",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Questo utilizza le informazioni dell'episodio provenienti dai metadata incorporati, se disponibili.",
|
||||
"ClientSettings": "Impostazioni del client"
|
||||
}
|
||||
|
|
|
@ -1467,5 +1467,8 @@
|
|||
"PlaybackErrorNoCompatibleStream": "Houve um erro na criação de perfil do cliente e o servidor não está enviando um formato de mídia compatível.",
|
||||
"EnableFastImageFadeInHelp": "Habilitar animações rápidas de aparecimento para imagens carregadas",
|
||||
"LabelDroppedFrames": "Quadros caídos:",
|
||||
"AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução."
|
||||
"AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNames": "Preferir as informações incorporadas nos arquivos dos episódios ao invés dos nomes",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Isso utiliza as informações dos episódios incorporadas nos metadados dos arquivos se estiverem disponíveis.",
|
||||
"ClientSettings": "Configurações do cliente"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue